diff --git a/build/Dockerfile.onix-adapter-deg b/build/Dockerfile.onix-adapter-deg new file mode 100644 index 00000000..fa3ba050 --- /dev/null +++ b/build/Dockerfile.onix-adapter-deg @@ -0,0 +1,52 @@ +# Dockerfile for building onix-adapter with DEG plugins +# This ensures the adapter and plugins are built with the same Go version +# and beckn-onix package versions for compatibility. +# +# Build from DEG repo root: +# docker build -f build/Dockerfile.onix-adapter-deg -t onix-adapter-deg \ +# --build-context beckn-onix=../beckn-onix . +# +# Or from parent directory containing both repos: +# docker build -f DEG/build/Dockerfile.onix-adapter-deg -t onix-adapter-deg \ +# --build-context beckn-onix=beckn-onix DEG + +FROM golang:1.24-bullseye AS builder + +WORKDIR /workspace + +# Copy beckn-onix source +COPY --from=beckn-onix . ./beckn-onix/ + +# Copy DEG plugins source +COPY plugins ./deg-plugins/ + +# Build onix-adapter server +WORKDIR /workspace/beckn-onix +RUN go mod download +RUN go build -o server cmd/adapter/main.go + +# Build standard beckn-onix plugins +RUN mkdir -p plugins +RUN ./install/build-plugins.sh + +# Build DEG plugins +WORKDIR /workspace/deg-plugins + +# Update go.mod to use local beckn-onix +RUN sed -i 's|=> ../../beckn-onix|=> /workspace/beckn-onix|g' go.mod +RUN go mod tidy + +# Build DEG ledger recorder plugin +RUN go build -buildmode=plugin -o /workspace/beckn-onix/plugins/degledgerrecorder.so ./degledgerrecorder/cmd/plugin.go + +# Create minimal runtime image +FROM cgr.dev/chainguard/wolfi-base +WORKDIR /app + +# Copy binary and all plugins (standard + DEG) +COPY --from=builder /workspace/beckn-onix/server . +COPY --from=builder /workspace/beckn-onix/plugins ./plugins + +EXPOSE 8081 + +CMD ["sh", "-c", "./server --config=${CONFIG_FILE}"] diff --git a/build/README.md b/build/README.md new file mode 100644 index 00000000..2d6addbb --- /dev/null +++ b/build/README.md @@ -0,0 +1,132 @@ +# DEG Build Scripts + +This directory contains build scripts and Docker configurations for the DEG Ledger Recorder plugin and onix-adapter-deg image. + +## Files + +| File | Description | +|------|-------------| +| `Dockerfile.onix-adapter-deg` | Dockerfile for building onix-adapter with DEG plugins | +| `build-multiarch.sh` | Build multi-arch Docker image (amd64 + arm64) | + +## Multi-Architecture Builds + +The `build-multiarch.sh` script builds Docker images for multiple architectures (linux/amd64 and linux/arm64) using Docker Buildx and QEMU emulation. + +### Prerequisites + +1. **Docker with Buildx support** + - Docker Desktop (macOS/Windows): Buildx is included + - Linux: Install Docker Engine 19.03+ with buildx plugin + +2. **QEMU** (for cross-architecture emulation) + - The script automatically installs QEMU user-mode emulation + - Or install manually: + ```bash + docker run --privileged --rm tonistiigi/binfmt --install all + ``` + +3. **beckn-onix repository** + - Script will prompt for path if not found at default location (`../beckn-onix`) + - Or set `BECKN_ONIX_ROOT` environment variable to skip prompt + +### Usage + +```bash +# Build and load to local Docker (current architecture only) +./build/build-multiarch.sh --load + +# Build for specific platform +./build/build-multiarch.sh --platform amd64 --load +./build/build-multiarch.sh --platform arm64 --load + +# Build and push to registry (multi-arch) +./build/build-multiarch.sh --push --registry docker.io/myuser + +# Build with custom tag +./build/build-multiarch.sh --push --registry ghcr.io/myorg --tag v1.0.0 + +# Show help +./build/build-multiarch.sh --help +``` + +### Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `BECKN_ONIX_ROOT` | (prompts if not found) | Path to beckn-onix repo | +| `IMAGE_NAME` | `onix-adapter-deg` | Docker image name | +| `IMAGE_TAG` | `p2p-multiarch-v3` | Docker image tag | +| `REGISTRY` | (none) | Registry prefix (e.g., `docker.io/user`) | +| `PLATFORMS` | `linux/amd64,linux/arm64` | Target platforms | +| `BUILDER_NAME` | `deg-multiarch` | Buildx builder name | + +### Examples + +**Local development (macOS Apple Silicon)** +```bash +# Build for your Mac's ARM64 architecture +./build/build-multiarch.sh --platform arm64 --load + +# Run locally +docker run -it --rm \ + -v $(pwd)/config:/app/config \ + -e CONFIG_FILE=/app/config/local.yaml \ + -p 8081:8081 \ + onix-adapter-deg:latest +``` + +**Build for production deployment** +```bash +# Build multi-arch and push to Docker Hub +export REGISTRY=docker.io/mycompany +export IMAGE_TAG=v1.2.3 +./build/build-multiarch.sh --push + +# Verify multi-arch manifest +docker buildx imagetools inspect docker.io/mycompany/onix-adapter-deg:v1.2.3 +``` + +**GitHub Actions CI/CD** + +See `.github/workflows/build-multiarch.yml` for automated multi-arch builds. + +## Go Plugin Compatibility + +**Important:** Go plugins require exact version matching: +- The plugin and host binary must be built with the **same Go version** +- The plugin and host must use the **same dependency versions** +- CGO must be enabled (`CGO_ENABLED=1`) + +The Dockerfile ensures compatibility by building both the adapter and plugins in the same build stage with the same Go version. + +## Troubleshooting + +### "exec format error" +You're trying to run an image built for a different architecture. Either: +- Build for your architecture: `--platform amd64` or `--platform arm64` +- Enable QEMU: `docker run --privileged --rm tonistiigi/binfmt --install all` + +### "plugin was built with a different version of package" +The plugin was built with a different Go version or dependency versions than the adapter. Rebuild both together using the Dockerfile. + +### "builder not found" +Create the buildx builder manually: +```bash +docker buildx create --name deg-multiarch --driver docker-container --bootstrap +docker buildx use deg-multiarch +``` + +### Slow builds on non-native architecture +QEMU emulation is slower than native builds. For faster CI: +- Use native runners when available (e.g., GitHub's `ubuntu-latest` for amd64) +- Consider using arm64 runners for arm64 builds +- Use build caching (`--cache-from type=gha`) + +## Architecture Notes + +The image supports: +- **linux/amd64**: Standard x86-64 servers (AWS EC2, GCP, most cloud VMs) +- **linux/arm64**: ARM64 servers (AWS Graviton, Apple Silicon Macs, Raspberry Pi 4+) + +The base image (`cgr.dev/chainguard/wolfi-base`) and Go image (`golang:1.24-bullseye`) both provide multi-arch support. diff --git a/build/build-multiarch.sh b/build/build-multiarch.sh new file mode 100755 index 00000000..7583f006 --- /dev/null +++ b/build/build-multiarch.sh @@ -0,0 +1,237 @@ +#!/bin/bash + +# Multi-Architecture Docker Build Script for DEG Ledger Recorder Plugin +# ====================================================================== +# Builds onix-adapter with DEG plugins for linux/amd64 and linux/arm64 +# +# Prerequisites: +# - Docker Desktop or Docker Engine with buildx support +# - QEMU user-static binaries (for cross-arch emulation) +# +# Usage: +# ./build-multiarch.sh # Build and load to local Docker (current arch only) +# ./build-multiarch.sh --push # Build multi-arch and push to registry +# ./build-multiarch.sh --platform amd64 # Build specific platform only +# +# Environment Variables: +# BECKN_ONIX_ROOT - Path to beckn-onix repo (will prompt if not set and default not found) +# IMAGE_NAME - Image name (default: onix-adapter-deg) +# IMAGE_TAG - Image tag (default: p2p-multiarch-v3) +# REGISTRY - Registry prefix (default: none, local build) +# PLATFORMS - Platforms to build (default: linux/amd64,linux/arm64) +# BUILDER_NAME - Buildx builder name (default: deg-multiarch) + +set -e + +# Script directory and paths +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +DEG_ROOT="$(dirname "$SCRIPT_DIR")" + +# Resolve beckn-onix path +if [ -n "$BECKN_ONIX_ROOT" ] && [ -d "$BECKN_ONIX_ROOT" ]; then + # Use environment variable if set and valid + : +else + # Prompt user for path + echo "" + read -p "Enter path to beckn-onix repository: " USER_BECKN_ONIX_PATH + + if [ -z "$USER_BECKN_ONIX_PATH" ]; then + echo "ERROR: beckn-onix path is required" + exit 1 + fi + + # Expand ~ to home directory + USER_BECKN_ONIX_PATH="${USER_BECKN_ONIX_PATH/#\~/$HOME}" + + if [ ! -d "$USER_BECKN_ONIX_PATH" ]; then + echo "ERROR: Directory not found: $USER_BECKN_ONIX_PATH" + exit 1 + fi + + BECKN_ONIX_ROOT="$USER_BECKN_ONIX_PATH" +fi + +# Configuration with defaults +IMAGE_NAME="${IMAGE_NAME:-onix-adapter-deg}" +IMAGE_TAG="${IMAGE_TAG:-p2p-multiarch-v3}" +REGISTRY="${REGISTRY:-}" +PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}" +BUILDER_NAME="${BUILDER_NAME:-deg-multiarch}" +DOCKERFILE="$SCRIPT_DIR/Dockerfile.onix-adapter-deg" + +# Parse arguments +PUSH_FLAG="" +LOAD_FLAG="" +while [[ $# -gt 0 ]]; do + case $1 in + --push) + PUSH_FLAG="--push" + shift + ;; + --load) + LOAD_FLAG="--load" + shift + ;; + --platform) + PLATFORMS="linux/$2" + shift 2 + ;; + --tag) + IMAGE_TAG="$2" + shift 2 + ;; + --registry) + REGISTRY="$2" + shift 2 + ;; + --help|-h) + echo "Usage: $0 [OPTIONS]" + echo "" + echo "Options:" + echo " --push Push to registry after build" + echo " --load Load into local Docker (single arch only)" + echo " --platform ARCH Build for specific platform (amd64, arm64)" + echo " --tag TAG Image tag (default: p2p-multiarch-v3)" + echo " --registry REG Registry prefix (e.g., docker.io/myuser)" + echo " --help Show this help message" + echo "" + echo "Environment Variables:" + echo " BECKN_ONIX_ROOT Path to beckn-onix repo (prompts if not set)" + echo " IMAGE_NAME Image name (default: onix-adapter-deg)" + echo " IMAGE_TAG Image tag (default: p2p-multiarch-v3)" + echo " REGISTRY Registry prefix" + echo " PLATFORMS Platforms (default: linux/amd64,linux/arm64)" + exit 0 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +# Construct full image name +if [ -n "$REGISTRY" ]; then + FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${IMAGE_TAG}" +else + FULL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}" +fi + +echo "============================================" +echo "Multi-Arch Build: DEG Ledger Recorder" +echo "============================================" +echo "DEG Root: $DEG_ROOT" +echo "Beckn-ONIX Root: $BECKN_ONIX_ROOT" +echo "Dockerfile: $DOCKERFILE" +echo "Image: $FULL_IMAGE" +echo "Platforms: $PLATFORMS" +echo "Builder: $BUILDER_NAME" +echo "============================================" + +# Verify Dockerfile exists +if [ ! -f "$DOCKERFILE" ]; then + echo "ERROR: Dockerfile not found at $DOCKERFILE" + exit 1 +fi + +# Step 1: Setup QEMU for cross-platform emulation +echo "" +echo ">>> Step 1: Setting up QEMU for cross-platform builds..." +docker run --privileged --rm tonistiigi/binfmt --install all 2>/dev/null || { + echo "Note: QEMU setup may already be configured or not needed" +} + +# Step 2: Create/use buildx builder +echo "" +echo ">>> Step 2: Setting up buildx builder..." +if ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then + echo "Creating new buildx builder: $BUILDER_NAME" + docker buildx create \ + --name "$BUILDER_NAME" \ + --driver docker-container \ + --driver-opt network=host \ + --bootstrap +else + echo "Using existing builder: $BUILDER_NAME" +fi + +docker buildx use "$BUILDER_NAME" + +# Step 3: Verify builder supports requested platforms +echo "" +echo ">>> Step 3: Verifying builder capabilities..." +docker buildx inspect --bootstrap + +# Step 4: Determine output mode +# - If pushing to registry: use --push (supports multi-arch) +# - If loading locally: use --load (single arch only) +# - If neither: outputs are kept in build cache + +OUTPUT_FLAG="" +if [ -n "$PUSH_FLAG" ]; then + OUTPUT_FLAG="$PUSH_FLAG" + echo "" + echo ">>> Mode: Build and push to registry" +elif [ -n "$LOAD_FLAG" ]; then + OUTPUT_FLAG="$LOAD_FLAG" + # --load only works with single platform + if [[ "$PLATFORMS" == *","* ]]; then + echo "WARNING: --load only supports single platform. Using current platform." + PLATFORMS="linux/$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')" + fi + echo "" + echo ">>> Mode: Build and load to local Docker (platform: $PLATFORMS)" +else + echo "" + echo ">>> Mode: Build only (use --push or --load to export)" + echo " Note: Images will be in build cache. Use --push to push to registry" + echo " or --load to load single-arch image to local Docker." +fi + +# Step 5: Build the image +echo "" +echo ">>> Step 4: Building multi-arch image..." +echo "Command:" +echo " docker buildx build \\" +echo " --platform $PLATFORMS \\" +echo " --file $DOCKERFILE \\" +echo " --build-context beckn-onix=$BECKN_ONIX_ROOT \\" +echo " --tag $FULL_IMAGE \\" +echo " $OUTPUT_FLAG \\" +echo " $DEG_ROOT" +echo "" + +docker buildx build \ + --platform "$PLATFORMS" \ + --file "$DOCKERFILE" \ + --build-context beckn-onix="$BECKN_ONIX_ROOT" \ + --tag "$FULL_IMAGE" \ + $OUTPUT_FLAG \ + "$DEG_ROOT" + +# Step 6: Report results +echo "" +echo "============================================" +echo "Build Complete!" +echo "============================================" +echo "Image: $FULL_IMAGE" +echo "Platforms: $PLATFORMS" + +if [ -n "$PUSH_FLAG" ]; then + echo "" + echo "Image pushed to registry. Verify with:" + echo " docker buildx imagetools inspect $FULL_IMAGE" +elif [ -n "$LOAD_FLAG" ]; then + echo "" + echo "Image loaded to local Docker. Verify with:" + echo " docker images $IMAGE_NAME" + echo " docker inspect $FULL_IMAGE | jq '.[0].Architecture'" +else + echo "" + echo "Image built in cache. To use:" + echo " - Push to registry: $0 --push --registry " + echo " - Load locally: $0 --load" +fi + +echo "============================================" diff --git a/docs/Onboarding_Users_in_Digital_Energy_Programs.md b/docs/Onboarding_Users_in_Digital_Energy_Programs.md new file mode 100644 index 00000000..c0669a0b --- /dev/null +++ b/docs/Onboarding_Users_in_Digital_Energy_Programs.md @@ -0,0 +1,464 @@ +# **Technical Specification: Multi-Channel Onboarding of Users into Digital Energy Programs** + +Version: 1.0 (Draft – Normative) + +--- + +## **Status of This Memo** + +This document defines the **technical specification** for onboarding users into Digital Energy Programs through multiple channels. +This is a **standards-track** document. + +--- + +## **Table of Contents** + +1. Scope +2. Normative References +3. Definitions +4. Architectural Overview +5. Identity & Authentication Specification +6. Asset Model Specification +7. Program Owner Specification (BPP Role) +8. Enrolment Channel Specification +9. Beckn-Based Enrollment Flow Specification +10. Enrollment Criteria Specification +11. Credential Specification +12. Registries +13. Security Considerations +14. Privacy Considerations +15. Compliance Requirements +16. Appendix (Message Structures) + +--- + +# **1. Scope** + +This specification defines the **protocols, message structures, identifiers, interactions, and requirements** for enrolling users into digital energy programs using: + +* **Utility Portals** +* **Certified Enrolment Agency Portals** +* **Network Participant Applications** using an **Onboarding SDK** + +The specification covers: + +* Identity and authentication +* Meter and DER association +* Program discovery and eligibility verification +* Consent acquisition +* Credential issuance +* Multi-utility onboarding +* Multi-persona handling +* Beckn protocol interactions for search → select → init → confirm + +This document is globally applicable and does not depend on any specific national identity scheme, tariff structure, or regulatory regime. + +--- + +# **2. Normative References** + +The following specifications are normative: + +* **Beckn Protocol 1.x / 2.0** — Discovery, Ordering, Fulfillment flows +* **W3C DID Core** +* **W3C Verifiable Credentials (VC Data Model)** +* **OpenID Connect Core** +* **RFC 6749 – OAuth 2.0** +* **RFC 8259 – JSON** +* **ISO/IEC 30141 – IoT Reference Architecture** +* **DEG Vision Document** (Identity, Verifiability, Interoperability principles) + +--- + +# **3. Definitions** + +### **3.1 User Identifier** + +One of: + +* National ID (e.g., Social Security Number, Aadhaar, SIN, BankID, etc.) +* Program-level Meter Identifier (UMID) +* Utility Customer Identifier + +### **3.2 Enrolment Agency (EA)** + +A utility-certified entity authorized to conduct onboarding flows. + +### **3.3 Program Owner** + +Entity operating a digital energy program. +In Beckn terms, Program Owner implements a **BPP**. + +### **3.4 Network Participant** + +Any BAP, BPP, NFO, EV app, DER app, or aggregator application integrating via the SDK. + +### **3.5 Behind-the-Meter (BTM) Appliances** + +Appliances consuming or producing energy through a user-side meter. + +--- + +# **4. Architectural Overview** + +The onboarding architecture comprises: + +## **4.1 Identity Layer** + +* OIDC-based unified Identity Provider (IdP) +* Federation with national ID or utility ID providers +* All login returns a `subject_id` + +## **4.2 Asset Layer** + +Defines relationships: + +* User ↔ Utility ↔ Accounts ↔ Meters ↔ Sites ↔ DERs (EV, solar, battery) + +## **4.3 Program Layer** + +Each Program Owner exposes: + +* Beckn Discovery endpoint +* Beckn Select + Init + Confirm to communicate eligibility and enrollment requirements +* Issuance of Program Enrollment Credential + +## **4.4 Channel Layer** + +Three approved channels: + +1. Utility Portal +2. Certified Enrolment Agency Portal +3. Network Participant App (via SDK) + +## **4.5 Credential Layer** + +All enrollment outcomes must issue: + +* **Program Enrollment Credential** as a Verifiable Credential + +--- + +# **5. Identity & Authentication Specification** + +### **5.1 Identity Provider (IdP) Requirements** + +The IdP MUST: + +1. Support OIDC Authorization Code Flow +2. Support at least three identifiers: + + * `national_id` + * `meter_id` (UMID) + * `utility_customer_id` +3. Issue ID Tokens containing: + +```json +{ + "sub": "", + "id_type": "national|meter|utility", + "meter_ids": [""], + "utility_customer_ids": ["<>"], + "acr": "assurance_level", + "iss": "https://idp.example.com" +} +``` + +### **5.2 Authentication Assurance** + +The IdP MUST support: + +* MFA (OTP, email, authenticator app, or national ID provider’s MFA) +* Federation with external trusted ID schemes + +--- + +# **6. Asset Model Specification** + +Every ecosystem MUST support the following data model: + +### **6.1 Entities** + +**User** + +* `subject_id` +* Contact info + +**Utility** + +* `utility_id` +* Service areas (CIM regions) + +**Meter** + +* `umid` (universal meter identity) +* `utility_meter_id` +* `utility_id` +* `site_id` + +**DER** + +* `der_id` +* `der_type` (EV, solarPV, battery, heat pump, V2G-EV) +* `primary_meter` (umid) +* `secondary_utility` for cross-utility usage + +**Program** + +* `program_id` +* Owned by Program Owner (BPP) + +--- + +# **7. Program Owner Specification (BPP Role)** + +### **7.1 Program Discovery** + +Program Owners MUST expose: + +* `POST /search` (Beckn Search) + Returns metadata: +* Supported personas +* Supported utilities +* Enrollment prerequisites + +### **7.2 Eligibility Evaluation** + +The **Init** API MUST return: + +```json +{ + "enrollment_criteria": { + "documents_required": [...], + "proof_required": [...], + "consents_required": [...], + "cross_utility_checks": [...], + "der_certification_required": true|false + }, + "next_steps": "collect_documents" +} +``` + +### **7.3 Enrollment Decision** + +The **Confirm** API MUST: + +* Approve or reject enrollment +* Issue Program Enrollment Credential + +--- + +# **8. Enrolment Channel Specification** + +Three channels MUST use identical Beckn interactions. + +### **8.1 Utility Portal** + +* MUST redirect to IdP for login +* MUST invoke `search → select → init → confirm` on Program Owner’s BPP +* MUST store final Program Enrollment Credential for user + +### **8.2 Certified Enrolment Agency Portal** + +* MUST redirect to IdP +* MUST call Program Owner BPP +* MUST include EA identity header: + +``` +X-Enrollment-Agency-ID: +``` + +### **8.3 Network Participant App with SDK** + +* MUST embed onboarding SDK +* MUST NOT directly call BPP +* SDK MUST perform all Beckn operations +* SDK MUST NOT override Enrollment decisions + +--- + +# **9. Beckn-Based Enrollment Flow Specification** + +### **9.1 Sequence** + +1. `search` – Program discovery +2. `on_search` – Program Owner BPP responds +3. `select` – User selects program +4. `on_select` – Program Owner returns preliminary eligibility +5. `init` – User submits identifiers, meters, DERs +6. `on_init` – Program Owner returns: + + * Required consents + * Required proofs + * Cross-utility checks +7. `confirm` – User submits consents + proofs +8. `on_confirm` – Program Owner issues enrollment credential + +### **9.2 Required Fields** + +**init.request** + +```json +{ + "subject_id": "did:example:123", + "meters": ["umid-123", "umid-456"], + "ders": ["der-ev-001"], + "cross_utility_info": ["utilityB"], + "persona_type": "consumer_multimeter" +} +``` + +--- + +# **10. Enrollment Criteria Specification** + +Program Owners MUST publish criteria **via Beckn Select/Init**, not via registries. + +Criteria MUST be returned as structured data: + +```json +{ + "criteria": { + "identity": ["national_id|meter_id|utility_id"], + "meter_association": true, + "der_certification": true, + "utility_ownership_verification": true, + "cross_utility_consent_required": true, + "v2g_control_consent_required": false + } +} +``` + +--- + +# **11. Credential Specification** + +### **11.1 Program Enrollment Credential (VC)** + +Required fields: + +```json +{ + "@context": ["https://www.w3.org/2018/credentials/v1", "https://dedi.global/energy-program/v1"], + "type": ["VerifiableCredential", "ProgramEnrollmentCredential"], + "issuer": "", + "credentialSubject": { + "subject_id": "", + "program_id": "", + "meters": [""], + "ders": [""], + "roles": ["consumer|prosumer|v2g-participant"], + "constraints": {...} + } +} +``` + +Must support **StatusList revocation**. + +--- + +# **12. Registries** + +Program discovery and criteria are **not registries**. + +The following registries **MUST** exist on `dedi.global`: + +### **12.1 Utility Registry** + +Contains: + +* Utility ID +* Public keys +* Service areas + +### **12.2 Enrolment Agency Registry** + +Contains: + +* EA ID +* Certification details +* Supported utilities +* Public signing keys + +### **12.3 Schema Registry** + +Contains: + +* Program Enrollment Credential schema +* Meter/DER schemas +* Consent schema + +Registries MUST be publicly accessible and versioned. + +--- + +# **13. Security Considerations** + +* All Beckn messages MUST be signed (non-repudiation). +* IdP must enforce MFA where legally required. +* DER control consents MUST be explicit. +* Cross-utility interactions MUST use mutual TLS. + +--- + +# **14. Privacy Considerations** + +* Programs MUST request minimum necessary data. +* National IDs must not be stored by Program Owners without legal basis. +* Cross-utility data sharing requires explicit consent. +* Users must be able to revoke participation at any time. + +--- + +# **15. Compliance Requirements** + +Entities MUST comply with: + +* Data protection laws (GDPR, CCPA, PDPA, etc.) +* Grid/utility regulatory frameworks +* Beckn protocol compliance +* Credential issuance standards +* Deg Vision principles (identity, verifiability, interoperability) + +--- + +# **16. Appendix: Message Structure Examples** + +## **16.1 Beckn init** + +```json +{ + "context": { "action": "init" }, + "message": { + "order": { + "provider": { "id": "program-owner-bpp" }, + "items": [{ "id": "program-id" }], + "fulfillments": [{ + "customer": { "id": "" }, + "instrument": { + "meters": ["umid-1"], + "ders": ["der-1"] + } + }] + } + } +} +``` + +## **16.2 Beckn on_confirm** + +```json +{ + "message": { + "order": { + "provider": { "id": "program-owner-bpp" }, + "id": "enrollment-12345", + "state": "CONFIRMED", + "documents": [{ + "type": "ProgramEnrollmentCredential", + "url": "https://utility.example.com/credential/123" + }] + } + } +} +``` diff --git a/docs/implementation-guides/v2/EV_Charging/EV_Charging.md b/docs/implementation-guides/v2/EV_Charging/EV_Charging.md index 27fd225f..ec45ba48 100644 --- a/docs/implementation-guides/v2/EV_Charging/EV_Charging.md +++ b/docs/implementation-guides/v2/EV_Charging/EV_Charging.md @@ -303,7 +303,7 @@ Specifically, for EV Charging, please use the following configuration: ### 11.2.3. 10.2.3 Performing a test EV charging transaction -Step 1 : Download the postman collection, from [here](/testnet/postman-collections/v2/EV_Charging/). +Step 1 : Download the postman collection, from [here](/testnet/ev-charging-devkit/postman/). Step 2 : Run API calls @@ -684,7 +684,7 @@ Note: Users can discover the charging station through off-network channels (such "WALLET" ], "beckn:offerAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/EvChargingOffer/v1/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld", "@type": "ChargingOffer", "tariffModel": "PER_KWH", "idleFeePolicy": { @@ -729,7 +729,7 @@ Note: Users can discover the charging station through off-network channels (such "CREDIT_CARD" ], "beckn:offerAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/EvChargingOffer/v1/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld", "@type": "ChargingOffer", "tariffModel": "PER_KWH", "idleFeePolicy": { diff --git a/docs/implementation-guides/v2/Onboarding/IG_Onboarding_users_in_digital_energy_programs.md b/docs/implementation-guides/v2/Onboarding/IG_Onboarding_users_in_digital_energy_programs.md new file mode 100644 index 00000000..2b35b6a0 --- /dev/null +++ b/docs/implementation-guides/v2/Onboarding/IG_Onboarding_users_in_digital_energy_programs.md @@ -0,0 +1,2775 @@ +# Implementation Guide: Multi-Channel Onboarding of Users into Digital Energy Programs + +Version 0.2 (Non-Normative) + +## Table of Contents +- [1. Introduction](#1-introduction) +- [2. Scope](#2-scope) +- [3. Terminology](#3-terminology) + - [3.1. Acronyms](#31-acronyms) +- [4. Terminology](#4-terminology) +- [5. Implementation Principles](#5-implementation-principles) +- [6. System Architecture Overview](#6-system-architecture-overview) +- [7. Identity and Authentication Implementation](#7-identity-and-authentication-implementation) + - [7.1. Authentication Flow](#71-authentication-flow) + - [7.2. OAuth2 Token Usage](#72-oauth2-token-usage) + - [7.3. Utility IdP API Examples](#73-utility-idp-api-examples) + - [7.4. MeterOwnershipCredential VC Issuance](#74-meterownershipcredential-vc-issuance) + - [7.5. Example Utility API Implementation](#75-example-utility-api-implementation) +- [8. Asset Mapping and Data Integration](#8-asset-mapping-and-data-integration) + - [8.1. Meter Discovery](#81-meter-discovery) + - [8.2. DER Discovery](#82-der-discovery) + - [8.3. Data Integration](#83-data-integration) +- [9. Beckn-Based Enrollment Implementation](#9-beckn-based-enrollment-implementation) + - [9.1. Standard Beckn Flow](#91-standard-beckn-flow) + - [9.2. Enrollment Flow Diagram](#92-enrollment-flow-diagram) + - [9.2.1. High-Level Overview (Both Flows)](#921-high-level-overview-both-flows) + - [9.2.2. OTP-Based Enrollment Flow (Detailed)](#922-otp-based-enrollment-flow-detailed) + - [9.2.3. OAuth2/OIDC-Based Enrollment Flow (Detailed)](#923-oauth2oidc-based-enrollment-flow-detailed) + - [9.2.4. Error Handling: No Meter Specified](#924-error-handling-no-meter-specified) +- [10. Channel-Specific Implementation Guides](#10-channel-specific-implementation-guides) + - [10.1. Utility Portal (UtilityPortal/BAP)](#101-utility-portal-utilityportalbap) + - [10.2. Enrolment Agency Portal (EA/BAP)](#102-enrolment-agency-portal-eabap) + - [10.3. Network Participant App (BAP)](#103-network-participant-app-bap) +- [11. Persona-Specific Implementation Guidance](#11-persona-specific-implementation-guidance) + - [11.1. Consumer – Single Household, Single Meter](#111-consumer--single-household-single-meter) + - [11.2. Consumer – Multiple Households, Multiple Meters](#112-consumer--multiple-households-multiple-meters) + - [11.3. Consumer – BTM Appliances via Home Meter](#113-consumer--btm-appliances-via-home-meter) + - [11.4. Consumer – BTM Appliances via Same Utility (e.g., neighbor’s meter)](#114-consumer--btm-appliances-via-same-utility-eg-neighbors-meter) + - [11.5. Consumer/Prosumer – BTM Appliances via Different Utility](#115-consumerprosumer--btm-appliances-via-different-utility) + - [11.6. Prosumer – Single Rooftop Solar Meter](#116-prosumer--single-rooftop-solar-meter) + - [11.7. Prosumer – Multiple Meters with Solar](#117-prosumer--multiple-meters-with-solar) + - [11.8. Prosumer – EV with V2G](#118-prosumer--ev-with-v2g) +- [12. Governance and Operational Guidance](#12-governance-and-operational-guidance) +- [13. Data Models and Storage Considerations](#13-data-models-and-storage-considerations) +- [14. Security and Privacy Implementation](#14-security-and-privacy-implementation) +- [15. Testing, Certification and Compliance](#15-testing-certification-and-compliance) +- [16. Deployment Topology Recommendations](#16-deployment-topology-recommendations) +- [17. Developer Tooling and SDK Recommendations](#17-developer-tooling-and-sdk-recommendations) +- [18. Appendix A – Sample Payloads](#18-appendix-a--sample-payloads) + - [18.1. Init Request](#181-init-request) + - [18.1.1. Example: OTP-Based Init Request](#1811-example-otp-based-init-request) + - [18.1.2. Example: OAuth2/OIDC-Based Init Request](#1812-example-oauth2oidc-based-init-request) + - [18.1.3. Example: Simple Consumer with Single Meter](#1813-example-simple-consumer-with-single-meter) + - [18.1.4. Example: Prosumer with Solar and Battery](#1814-example-prosumer-with-solar-and-battery) + - [18.2. On\_Init Response](#182-on_init-response) + - [18.2.1. Example: OTP-Based On\_Init Response](#1821-example-otp-based-on_init-response) + - [18.2.2. Example: OAuth2/OIDC-Based On\_Init Response](#1822-example-oauth2oidc-based-on_init-response) + - [18.2.3. Example: Successful Verification, No Conflicts](#1823-example-successful-verification-no-conflicts) + - [18.2.4. Example: Enrollment Conflict Detected](#1824-example-enrollment-conflict-detected) + - [18.3. Confirm Request](#183-confirm-request) + - [18.3.1. Example: OTP-Based Confirm Request](#1831-example-otp-based-confirm-request) + - [18.3.2. Example: OAuth2/OIDC-Based Confirm Request](#1832-example-oauth2oidc-based-confirm-request) + - [18.3.3. Example: Confirm with Enrollment Dates](#1833-example-confirm-with-enrollment-dates) + - [18.4. On\_Confirm Response](#184-on_confirm-response) + - [18.4.1. Example: OTP-Based On\_Confirm Response (Success)](#1841-example-otp-based-on_confirm-response-success) + - [18.4.2. Example: OAuth2/OIDC-Based On\_Confirm Response (Success)](#1842-example-oauth2oidc-based-on_confirm-response-success) + - [18.4.3. Example: No Meter Specified Error](#1843-example-no-meter-specified-error) + - [18.4.4. Example: Successful Enrollment with Credential](#1844-example-successful-enrollment-with-credential) + - [18.5. Error Response Example](#185-error-response-example) + - [18.5.1. Example: Credential Verification Failed](#1851-example-credential-verification-failed) + - [18.6. Consent Revocation](#186-consent-revocation) + - [18.6.1. Example: Consent Revocation Request](#1861-example-consent-revocation-request) + - [18.6.2. Example: Consent Revocation Response](#1862-example-consent-revocation-response) + - [18.7. Unenrollment](#187-unenrollment) + - [18.7.1. Example: Unenrollment Request](#1871-example-unenrollment-request) + - [18.7.2. Example: Unenrollment Response](#1872-example-unenrollment-response) +- [19. Appendix B – Multi-Utility Interaction Patterns](#19-appendix-b--multi-utility-interaction-patterns) +- [20. Appendix C – Error Handling Patterns](#20-appendix-c--error-handling-patterns) + +Table of contents and section auto-numbering was done using [Markdown-All-In-One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) vscode extension. Specifically `Markdown All in One: Create Table of Contents` and `Markdown All in One: Add/Update section numbers` commands accessible via vs code command pallete. + +Example jsons were imported directly from source of truth elsewhere in this repo inline by inserting the pattern below within all json expand blocks, and running this [script](/scripts/embed_example_json.py), e.g. `python3 scripts/embed_example_json.py path_to_markdown_file.md`. + +``` +
txt_with_json_keyword + +
+``` + +--- + +## 1. Introduction + +This Implementation Guide explains how to build and operate a multi-channel onboarding system for Digital Energy Programs such as: + +* Peer-to-Peer (P2P) energy trading +* Demand flexibility or demand response +* Virtual Power Plants (VPPs) +* Community solar and other tariff or incentive programs + +A successful onboarding process must confirm: + +* The identity of the user +* The user’s relationship to one or more utilities +* The meters and sites associated with the user +* Any Behind-the-Meter (BTM) devices or Distributed Energy Resources (DERs) +* The user’s eligibility for a given program +* The necessary consents for data use, telemetry, or control rights + +This guide provides engineering and operational recommendations to implement the multi-channel model defined in the Technical Specification. + +--- + +## 2. Scope + +This document covers: + +* Engineering patterns for multi-channel onboarding +* Identity and login integration +* Meter and DER mapping +* How to use Beckn flows for onboarding +* Guidance for utility portals, Enrolment Agency portals, and SDK-based flows +* Persona-specific onboarding patterns +* Governance requirements for utilities and EAs +* Data, security, and compliance recommendations + +This guide does not redefine schemas or protocol rules; those remain in the Technical Specification. + +--- + +## 3. Terminology + +Below is a consolidated terminology set used throughout this guide. + +### 3.1. Acronyms + +| Acronym | Full Form | Definition | +|---------|-----------|------------| +| **Utility IdP** | Utility Identity Provider | The OIDC-based identity provider operated by or on behalf of a utility. Handles user authentication (OTP, password, etc.) and issues OAuth2 tokens and Verifiable Credentials. | +| **Program Owner BPP** | Program Owner Beckn Provider Platform | The BPP implementation operated by the Program Owner (utility or energy program operator). Also referred to as UtilityBPP or Orchestrator in some contexts. Handles enrollment flows and issues Program Enrollment Credentials. | + +--- + +## 4. Terminology + +| Term | Definition | +| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | +| User / End User | A person or organization participating in a digital energy program (consumer, prosumer, EV owner, business). | +| Utility | An electricity provider responsible for metering, billing, and grid operations. | +| Program Owner | The entity offering a digital energy program (P2P, Flex, VPP). Operates the Program Owner BPP (also called UtilityBPP/Orchestrator) for enrollment flows. | +| Utility IdP | Utility Identity Provider. OIDC-based identity provider that handles user authentication and issues OAuth2 tokens and Verifiable Credentials. | +| Program Owner BPP | Program Owner Beckn Provider Platform. The BPP implementation that handles enrollment flows and issues Program Enrollment Credentials. Also referred to as UtilityBPP or Orchestrator. | +| Enrolment Agency (EA) | A utility-certified entity authorized to onboard users, either via self-service or assisted flows. | +| Network Participant | Any Beckn-enabled application (BAP, BPP, NFO, EV app, DER app) that can trigger onboarding but is not a certified EA. | +| Network Facilitator Organization (NFO) | A neutral governance or orchestration entity in a digital energy network. Does not make eligibility decisions. | +| National Identity | A government-backed identity (e.g., Social Security Number, Aadhaar, BankID, SingPass) used via federated IdPs. | +| Utility Customer Identifier | A unique customer or account number issued by a utility. | +| Program-Level Meter Identifier (UMID) | A universal, utility-agnostic meter identity used across programs. | +| DER Identifier (DER-ID) | Unique program-level identifier for a distributed energy resource. | +| Subject Identifier (subject_id) | The unified identifier for a user across utilities, apps, and programs (often a DID or OIDC `sub`). | +| Meter | A physical electricity meter tracking consumption, generation, or net flow. | +| Behind-the-Meter (BTM) Appliance | A device consuming or producing energy behind a user’s meter (e.g., EV charging at home). | +| Distributed Energy Resource (DER) | Any distributed asset such as solar PV, EV, home batteries, V2G, or smart loads. | +| EVSE | Electric Vehicle Supply Equipment (charging station). | +| Digital Energy Program | Any structured offering such as P2P trading, Flex, VPP, Community Solar, or special tariffs. | +| Program Enrollment | Approval for a user to join a program, issued as a Verifiable Credential. | +| Eligibility Criteria | Conditions needed for joining a program, returned dynamically via Beckn select/init flows. | +| Consent | Authorization for data sharing, telemetry, control rights, or cross-utility interactions. | +| BAP (Beckn Application Platform) | A consumer-facing Beckn application. | +| BPP (Beckn Provider Platform) | A provider system responding to Beckn calls. The Program Owner serves as a BPP for onboarding. | +| Discover / Select / Init / Confirm | The four core Beckn workflow steps used for onboarding. | +| Context Object | Beckn metadata (transaction ID, timestamp, domain, signature info). | +| Utility Portal | User-facing portal run by a utility for onboarding. | +| Enrolment Agency Portal | A certified EA’s portal for onboarding users. | +| Onboarding SDK | A software kit embedded inside apps to execute standardized onboarding flows. | +| Network Participant Application | Any application embedding the onboarding SDK (EV, DER, aggregator, smart home apps). | +| Program Enrollment Credential | A Verifiable Credential proving program participation. | +| Revocation List | Mechanism for invalidating credentials. | +| DER Certification | Proof that a DER asset (solar, EVSE, etc.) is compliant and safely installed. | +| Audit Trail | Signed, immutable record of onboarding-related actions. | +| Authorization | Permission to onboard users or to control DER assets. | +| Capability | Functional characteristics an entity or device supports (e.g., V2G capability). | + + + +--- + +## 5. Implementation Principles + +1. All onboarding channels must route to the same Program Owner backend. +2. Onboarding follows a consistent order: + identity → meters → DERs → program evaluation → enrollment. +3. Eligibility criteria must be fetched dynamically from the Program Owner. +4. All telemetry, cross-utility, and DER control actions require explicit consent. +5. Beckn discover/select/init/confirm flows should be reused without deviation. +6. User inputs should be minimized through auto-discovery where possible. + +--- + +## 6. System Architecture Overview + +A typical implementation includes: + +* An Identity Provider (IdP) +* An Onboarding Orchestration Layer (portal or SDK backend) +* A Program Owner BPP (eligibility logic and enrollment credential issuer) +* Utility Core Systems (CIS, MDM, DER registry, billing) +* A credential issuance and verification subsystem + +Architecture Diagram (Mermaid): + +```mermaid +graph TD + subgraph UserSide[User and Apps] + U[User] --> AP1[Utility Portal] + U --> AP2[Enrolment Agency Portal] + U --> AP3[Network Participant App] + end + + AP1 -->|OIDC| IDP[Identity Provider] + AP2 -->|OIDC| IDP + AP3 --> SDK[Onboarding SDK] + SDK -->|OIDC| IDP + + AP1 -->|Beckn| BPP[Program Owner BPP] + AP2 -->|Beckn| BPP + SDK -->|Beckn| BPP + + BPP --> CIS[Customer Information System] + BPP --> MDM[Meter Data Management] + BPP --> DER[DER Registry] + BPP --> BILL[Billing System] + BPP --> VCISS[VC Issuer / Revocation Service] +``` + +--- + +## 7. Identity and Authentication Implementation + +The Utility IdP and Program Owner BPP work together to provide a seamless authentication and enrollment experience. Authentication can be integrated with the Beckn enrollment flow in two ways: + +### 7.1. Authentication Flow + +The enrollment flow supports two authentication methods, both embedded within the Beckn protocol messages. + +**Important: Authentication is NOT required for /discover and /select.** Users can browse programs anonymously. Authentication is only required starting from `/init`. + +**Option 1: OTP-Based Authentication (BPP-Orchestrated)** +1. User browses programs via `/discover` and `/select` (anonymous, no auth required) +2. User decides to enroll → provides mobile number to UtilityPortal/BAP +3. BAP sends `init` request with `userAuth: { authMethod: "OTP", mobile: "..." }` +4. Program Owner BPP calls Utility IdP to generate OTP +5. User receives OTP via SMS and enters it in the portal +6. BAP sends `confirm` request with `userAuth: { authMethod: "OTP", mobile, nguid, otp }` and `meters` array +7. Program Owner BPP calls Utility IdP to verify OTP and retrieve meter/p2pdetails +8. BPP creates enrollment and returns credential + +**Option 2: OAuth2/OIDC Authentication (Deferred until /init)** +1. User browses programs via `/discover` and `/select` (anonymous, no auth required) +2. User decides to enroll → BAP redirects to Utility IdP for OAuth2/OIDC login +3. User authenticates with Utility IdP (receives accessToken, idToken) +4. BAP sends `init` request with `userAuth: { authMethod: "OIDC", accessToken, idToken }` +5. Program Owner BPP validates token with Utility IdP, retrieves user's meters +6. BPP returns meters list in `/on_init` response +7. User selects meters → BAP sends `confirm` request with tokens and `meters` array +8. BPP creates enrollment and returns credential + +### 7.2. OAuth2 Token Usage + +**IMPORTANT: OAuth2/OIDC tokens are transmitted in the Beckn message payload (`orderAttributes.userAuth`), NOT in HTTP Authorization headers.** + +This design ensures: +- Authentication is part of the business flow, not transport layer +- BPP can orchestrate authentication with multiple IdPs +- Consistent handling across different authentication methods (OTP vs OAuth2) + +**Example Beckn Request with OAuth2 Token in Payload:** +```http +POST /beckn/init HTTP/1.1 +Host: program-owner-bpp.example.com +Content-Type: application/json +X-Gateway-Authorization: + +{ + "context": { + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "action": "init", + ... + }, + "message": { + "order": { + "orderAttributes": { + "@context": ".../EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + "idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." + } + } + } + } +} +``` + +**Example OTP-Based Request:** +```json +{ + "message": { + "order": { + "orderAttributes": { + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "mobile": "+919999999999" + } + } + } + } +} +``` + +**Example OAuth2 Token Payload (decoded JWT):** +```json +{ + "sub": "did:example:user-12345", + "aud": "program-owner-bpp", + "iss": "https://utility-idp.example.com", + "iat": 1704067200, + "exp": 1704070300, + "nonce": "abc123", + "acr": "2", + "amr": ["otp"], + "meterId": "umid-001", + "caNumber": "CA123456789" +} +``` + +**Standard OAuth2 Token Fields:** +- `sub`: Subject identifier (user's unique ID) +- `aud`: Audience (intended recipient, e.g., Program Owner BPP) +- `iss`: Issuer (Utility IdP URL) +- `iat`: Issued at (Unix timestamp) +- `exp`: Expiration time (Unix timestamp) +- `nonce`: Random value to prevent replay attacks +- `acr`: Authentication Context Class Reference (assurance level) +- `amr`: Authentication Methods References (e.g., ["otp", "password"]) + +**Custom Claims (Utility-Specific):** +- `meterId`: Meter identifier (UMID) +- `caNumber`: Customer account number +- Additional utility-specific claims as needed + +### 7.3. Utility IdP API Examples + +The Utility IdP provides APIs for OTP generation, verification, and consumer validation. **These APIs are called by the Program Owner BPP** (not the BAP) to orchestrate authentication. This design allows: +- BPP to manage authentication flow centrally +- Support for multiple Utility IdPs in multi-utility scenarios +- Consistent authentication regardless of BAP implementation + +The exact API structure may vary by utility, but the following represents common patterns: + +**Generic OTP Generation Request:** +```http +POST /api/v1/otp/generate +Authorization: Bearer +Content-Type: application/json + +{ + "mobileNumber": "+1234567890", + "requestId": "req-12345-67890" +} +``` + +**Generic OTP Generation Response:** +```json +{ + "status": "success", + "requestId": "req-12345-67890", + "otpSessionId": "session-abc123", + "expiresIn": 300, + "message": "OTP sent to registered mobile number" +} +``` + +**Generic OTP Verification Request:** +```http +POST /api/v1/otp/verify +Authorization: Bearer +Content-Type: application/json + +{ + "otpSessionId": "session-abc123", + "otp": "123456", + "mobileNumber": "+1234567890" +} +``` + +**Generic OTP Verification Response:** +```json +{ + "status": "success", + "verified": true, + "verifiedAt": "2024-10-15T10:35:05Z", + "meters": [ + { + "meterId": "umid-001", + "caNumber": "CA123456789", + "meterNumber": "METER987654321", + "address": "123 Main Street", + "sanctionedLoad": 5.0, + "connectionType": "residential" + }, + { + "meterId": "umid-002", + "caNumber": "CA123456790", + "meterNumber": "METER987654322", + "address": "456 Oak Avenue", + "sanctionedLoad": 10.0, + "connectionType": "commercial" + } + ], + "p2pdetails": { + "usertype": "prosumer", + "isp2pactive": false, + "iscaactive": false, + "sdload": "5.0", + "cuflimit": "10.0" + }, + "meterOwnershipCredential": { + "credentialId": "vc-meter-ownership-001", + "type": "MeterOwnershipCredential", + "format": "VC-JWT", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." + } +} +``` + +**Note:** The `accessToken` is optional in the response. The BPP may or may not receive an OAuth2 token from the Utility IdP. The critical data returned is the `meters` array and optional `p2pdetails` (additionalAttributes) which are passed to the BAP in the `on_confirm` response. + +**Generic Consumer Validation Request:** +```http +POST /api/v1/consumer/validate +Authorization: Bearer +Content-Type: application/json + +{ + "caNumber": "CA123456789", + "mobileNumber": "+1234567890", + "userType": "CONSUMER" +} +``` + +**Generic Consumer Validation Response:** +```json +{ + "status": "success", + "consumer": { + "caNumber": "CA123456789", + "meterNumber": "METER987654321", + "name": "John Doe", + "address": "123 Main Street", + "connectionStatus": "ACTIVE", + "sanctionLoad": 5.0, + "meterType": "SMART_METER" + } +} +``` + +### 7.4. MeterOwnershipCredential VC Issuance + +After successful OTP verification and consumer validation, the Utility IdP issues a `MeterOwnershipCredential` Verifiable Credential. This VC is then included in the Beckn `init` request's `orderAttributes.meterOwnershipCredential` field. + +**Example MeterOwnershipCredential VC (decoded JWT payload):** +```json +{ + "vc": { + "@context": ["https://www.w3.org/2018/credentials/v1"], + "type": ["VerifiableCredential", "MeterOwnershipCredential"], + "credentialSubject": { + "id": "did:example:user-12345", + "meterId": "umid-001", + "utilityId": "utility-example-001", + "caNumber": "CA123456789", + "meterNumber": "METER987654321", + "ownershipStatus": "OWNER", + "validFrom": "2024-01-01T00:00:00Z", + "validUntil": "2025-12-31T23:59:59Z" + }, + "issuanceDate": "2024-10-15T10:25:00Z" + }, + "iss": "did:example:utility-idp", + "iat": 1704067200 +} +``` + +This VC proves that the user (identified by `subject_id` from OAuth2 token) owns the specified meter/CA, as verified through the OTP flow with the Utility IdP. + +### 7.5. Example Utility API Implementation + +For reference, the following section shows an example of how a specific utility might implement these APIs. **Note:** This is for illustration only; actual utility implementations may vary. + +
+Example Utility API Implementation (Click to expand) + +**Example: Utility-Specific OTP API** + +Some utilities may require field-level encryption for security. The following shows an example pattern: + +**GenerateOTP Request (with encryption):** +```http +POST /api/integration/otp/generate +Content-Type: application/json + +{ + "sms_id": "ENC[base64_encrypted_sms_id]", + "mobile_no": "ENC[base64_encrypted_mobile_number]", + "username": "ENC[base64_encrypted_username]" +} +``` + +**GenerateOTP Response:** +```json +{ + "message": "SUCCESS", + "Response_code": "200", + "sessionId": "session-12345-67890" +} +``` + +**VerifyOTP Request (with encryption):** +```http +POST /api/integration/otp/verify +Content-Type: application/json + +{ + "sms_id": "ENC[base64_encrypted_sms_id]", + "mobile_no": "ENC[base64_encrypted_mobile_number]", + "username": "ENC[base64_encrypted_username]", + "sessionId": "session-12345-67890", + "otp": "ENC[base64_encrypted_otp]" +} +``` + +**ValidateConsumer Request (with encryption):** +```http +POST /api/integration/consumer/validate +Content-Type: application/json + +{ + "cano": "ENC[base64_encrypted_ca_number]", + "mobile_no": "ENC[base64_encrypted_mobile_number]", + "USERTYPE": "ENC[base64_encrypted_user_type]", + "FLAG": "ENC[base64_encrypted_flag]", + "ADDTNL1": "ENC[base64_encrypted_additional1]", + "ADDTNL2": "ENC[base64_encrypted_additional2]" +} +``` + +**ValidateConsumer Response (decrypted):** +```json +{ + "CA": "CA123456789", + "METER": "METER987654321", + "NAME": "John Doe", + "ADDRESS": "123 Main Street", + "CON_STATUS": "ACTIVE", + "Sanction_load": 5.0 +} +``` + +**Note:** Field-level encryption (AES-256-CBC) may be required by some utilities for compliance. The encryption keys and algorithms are typically provided by the utility as part of the integration documentation. + +
+ +--- + +## 8. Asset Mapping and Data Integration + +### 8.1. Meter Discovery + +Utility Portal: call CIS/MDM. +EA Portal: call a protected utility Meter API with user token. +SDK: rely on BPP’s Beckn init to resolve meter associations. + +### 8.2. DER Discovery + +Sources include: + +* Utility DER registries +* EV or OEM backends +* Inverter, battery, or smart home systems +* User declarations (with certification uploads) + +### 8.3. Data Integration + +Typical integrations: + +* CIS/CRM for customer accounts +* MDM for meter–subject relationships +* DER registry or asset database +* EV charging platforms if relevant + +--- + +## 9. Beckn-Based Enrollment Implementation + +### 9.1. Standard Beckn Flow + +1. discover +2. on_discover +3. select +4. on_select +5. init +6. on_init +7. confirm +8. on_confirm + +### 9.2. Enrollment Flow Diagram + +The enrollment flow supports two authentication methods embedded within the Beckn protocol: +1. **OTP-based authentication** - BPP orchestrates OTP flow with Utility IdP +2. **OAuth2/OIDC authentication** - User authenticates at /init, token passed in message payload + +**Key Design Principles:** +- **Anonymous discovery**: `/discover` and `/select` do NOT require authentication - users can browse programs freely +- **Authentication at /init**: Authentication is only required when user decides to enroll (at `/init` call) +- Authentication credentials (OTP or OAuth2 tokens) are passed in **message payload** (`orderAttributes.userAuth`), NOT in HTTP headers +- Program Owner BPP orchestrates authentication by calling Utility IdP +- `/on_init` response includes **list of user's meters** for selection +- After verification, BPP returns meters array and optional p2pdetails (additionalAttributes) +- If no meters specified in `/confirm`, error response includes available meters for user selection + +#### 9.2.1. High-Level Overview (Both Flows) + +```mermaid +sequenceDiagram + participant User + participant BAP as UtilityPortal/BAP + participant BPP as Program Owner BPP + participant IdP as Utility IdP + + rect rgb(240, 248, 255) + Note over User,IdP: Phase 1: Anonymous Discovery (common) + User->>BAP: Browse programs + BAP->>BPP: /discover, /select + BPP-->>BAP: Programs & details + end + + rect rgb(255, 250, 240) + Note over User,IdP: Phase 2: Authentication (at /init) + alt OTP Flow + BAP->>BPP: /init (mobile) + BPP->>IdP: generateOTP + IdP->>User: SMS OTP + BPP-->>BAP: /on_init (nguid) + User->>BAP: Enter OTP + else OAuth2/OIDC Flow + User->>IdP: Login (redirect) + IdP-->>BAP: Tokens + BAP->>BPP: /init (tokens) + BPP->>IdP: Validate + BPP-->>BAP: /on_init (meters list) + end + end + + rect rgb(240, 255, 240) + Note over User,IdP: Phase 3: Enrollment (common) + User->>BAP: Select meters + BAP->>BPP: /confirm (userAuth + meters) + BPP->>IdP: Verify (OTP) or Validate (token) + BPP-->>BAP: /on_confirm (credential, p2pdetails) + BAP-->>User: Enrollment complete + end +``` + +The detailed flows below show the full message payloads for each authentication method. + +#### 9.2.2. OTP-Based Enrollment Flow (Detailed) + +```mermaid +sequenceDiagram + participant User + participant BAP as UtilityPortal/BAP + participant BPP as Program Owner BPP + participant UtilityIdP as Utility IdP + + Note over User,UtilityIdP: Phase 1: Discovery & Program Selection + User->>BAP: Request program discovery + BAP->>BPP: POST /discover + BPP-->>BAP: /on_discover (available programs) + BAP->>User: Show programs + User->>BAP: Select program + BAP->>BPP: POST /select + BPP-->>BAP: /on_select (program details) + + Note over User,UtilityIdP: Phase 2: OTP Authentication (within Beckn init) + User->>BAP: Enter mobile number + BAP->>BPP: POST /init
orderAttributes.userAuth: {
authMethod: "OTP",
mobile: "+919999999999"
} + + BPP->>UtilityIdP: generateOTP(mobile) + UtilityIdP->>User: SMS with OTP + UtilityIdP-->>BPP: { nguid, expiresAt } + + BPP-->>BAP: /on_init
orderAttributes.userAuth: {
authMethod: "OTP",
nguid: "session-token",
message: "OTP sent",
expiresAt: "..."
} + + BAP->>User: Show OTP input + User->>BAP: Enter OTP + + Note over User,UtilityIdP: Phase 3: OTP Verification & Enrollment (within Beckn confirm) + BAP->>BPP: POST /confirm
orderAttributes: {
userAuth: {
authMethod: "OTP",
mobile: "+919999999999",
nguid: "session-token",
otp: "123456"
},
meters: [{ meterId: "umid-001" }]
} + + BPP->>UtilityIdP: verifyOTP(mobile, nguid, otp) + UtilityIdP->>UtilityIdP: Validate consumer + UtilityIdP-->>BPP: { verified: true,
meters: [...],
p2pdetails: {...} } + + BPP->>BPP: Create enrollment,
issue ProgramEnrollmentCredential + + BPP-->>BAP: /on_confirm
orderAttributes: {
userAuth: { verified: true },
enrollmentId: "...",
credential: { ... },
additionalAttributes: { p2pdetails: {...} }
} + + BAP-->>User: Enrollment successful +``` + +#### 9.2.3. OAuth2/OIDC-Based Enrollment Flow (Detailed) + +For OAuth2/OIDC flow, **authentication is NOT required for /discover and /select**. User can browse programs anonymously, then authenticate at /init: + +```mermaid +sequenceDiagram + participant User + participant BAP as UtilityPortal/BAP + participant BPP as Program Owner BPP + participant UtilityIdP as Utility IdP + + Note over User,UtilityIdP: Phase 1: Anonymous Discovery (NO authentication required) + User->>BAP: Browse available programs + BAP->>BPP: POST /discover
(no userAuth needed) + BPP-->>BAP: /on_discover (available programs) + BAP->>User: Show programs + User->>BAP: Select program + BAP->>BPP: POST /select
(no userAuth needed) + BPP-->>BAP: /on_select (program details, requirements) + BAP->>User: Show program details + + Note over User,UtilityIdP: Phase 2: User decides to enroll → Authentication at /init + User->>BAP: Click "Enroll" → Redirect to IdP + BAP->>UtilityIdP: OAuth2/OIDC login redirect + User->>UtilityIdP: Login (credentials) + UtilityIdP-->>BAP: accessToken, idToken (via callback) + + Note over User,UtilityIdP: Phase 3: Init with OAuth2 tokens (first authenticated call) + BAP->>BPP: POST /init
orderAttributes.userAuth: {
authMethod: "OIDC",
accessToken: "eyJ...",
idToken: "eyJ..."
} + + BPP->>UtilityIdP: Validate token (introspection/JWKS) + UtilityIdP-->>BPP: { valid: true,
subject: "user-123",
meters: [...],
p2pdetails: {...} } + + BPP-->>BAP: /on_init
orderAttributes: {
userAuth: {
authMethod: "OIDC",
verified: true,
subject: "user-123",
issuer: "https://..."
},
meters: [
{ meterId: "umid-001", sanctionedLoad: 5.0 },
{ meterId: "umid-002", sanctionedLoad: 10.0 }
]
} + + BAP->>User: Show user's meters & consents + + Note over User,UtilityIdP: Phase 4: Confirm enrollment with selected meters + User->>BAP: Select meters, accept consents + BAP->>BPP: POST /confirm
orderAttributes: {
userAuth: {
authMethod: "OIDC",
accessToken: "eyJ..."
},
meters: [{ meterId: "umid-001" }]
} + + BPP->>BPP: Create enrollment + + BPP-->>BAP: /on_confirm
orderAttributes: {
enrollmentId: "...",
credential: { ... },
additionalAttributes: { p2pdetails: {...} }
} + + BAP-->>User: Enrollment successful +``` + +**Key Points:** +- `/discover` and `/select` are **anonymous** - no authentication required +- Authentication happens at `/init` - this is when BPP validates token and retrieves user's meters +- `/on_init` response includes the **list of meters** belonging to the user +- BAP displays meters to user for selection before `/confirm` + +#### 9.2.4. Error Handling: No Meter Specified + +If `userAuth` is verified but `meters` array is empty or missing in confirm request, BPP returns an error **with the list of available meters** so the user can select: + +```mermaid +sequenceDiagram + participant BAP as UtilityPortal/BAP + participant BPP as Program Owner BPP + + BAP->>BPP: POST /confirm
orderAttributes: {
userAuth: { ... },
meters: [] // Empty!
} + + BPP-->>BAP: /on_confirm
error: {
code: "BIZ_NO_METER_SPECIFIED",
message: "No meter specified",
details: {
path: "$.message.order.orderAttributes.meters",
availableMeters: [
{ meterId: "umid-001", sanctionedLoad: 5.0 },
{ meterId: "umid-002", sanctionedLoad: 10.0 }
]
}
} + + BAP->>User: Show available meters
for selection + User->>BAP: Select meter(s) + BAP->>BPP: POST /confirm (retry)
meters: [{ meterId: "umid-001" }] +``` + +**Error Response JSON Example:** +```json +{ + "error": { + "code": "BIZ_NO_METER_SPECIFIED", + "message": "No meter specified for enrollment. Please select from available meters.", + "details": { + "path": "$.message.order.orderAttributes.meters", + "availableMeters": [ + { + "meterId": "umid-001", + "meterNumber": "METER987654321", + "address": "123 Main Street", + "sanctionedLoad": 5.0, + "connectionType": "residential" + }, + { + "meterId": "umid-002", + "meterNumber": "METER987654322", + "address": "456 Oak Avenue", + "sanctionedLoad": 10.0, + "connectionType": "commercial" + } + ] + } + } +} +``` + +This allows the BAP to display the user's meters and let them select which meter(s) to enroll, then retry the `/confirm` request. + +--- + +## 10. Channel-Specific Implementation Guides + +### 10.1. Utility Portal (UtilityPortal/BAP) + +The Utility Portal acts as a Beckn Application Platform (BAP) and is the primary user interface: + +* Collects user input (mobile number for OTP, or OAuth2 tokens) +* Passes authentication credentials to BPP via `orderAttributes.userAuth` +* **Does NOT directly call Utility IdP** for OTP generation/verification (BPP orchestrates this) +* Displays meters returned from BPP after authentication +* Collects meter selection from user for `meters` array in confirm request +* Displays p2pdetails and enrollment results from BPP + +### 10.2. Enrolment Agency Portal (EA/BAP) + +* Acts as BAP on behalf of users +* Collects user's mobile number for OTP flow +* Passes authentication to BPP (BPP handles IdP integration) +* Must log all actions for audit +* Supports assisted onboarding for complex personas + +### 10.3. Network Participant App (BAP) + +BAP responsibilities: + +* Collect authentication credentials (mobile for OTP, or OAuth2 tokens) +* Pass credentials to BPP in `orderAttributes.userAuth` +* Run Beckn flows (discover → select → init → confirm) +* Manage session and state +* Display meters and collect user selection +* Relay enrollment outcome to host app + +App responsibilities: + +* Trigger onboarding from appropriate context +* Store only non-sensitive results +* Never bypass BPP decisions +* **Never call Utility IdP directly** (BPP orchestrates authentication) + +--- + +## 11. Persona-Specific Implementation Guidance + +### 11.1. Consumer – Single Household, Single Meter + +Straightforward auto-discovery; minimal input required. + +### 11.2. Consumer – Multiple Households, Multiple Meters + +Portal must display meter–program matrix. + +### 11.3. Consumer – BTM Appliances via Home Meter + +SDK initiated from EV or smart home app. + +### 11.4. Consumer – BTM Appliances via Same Utility (e.g., neighbor’s meter) + +Requires two-party consent. + +### 11.5. Consumer/Prosumer – BTM Appliances via Different Utility + +Requires cross-utility identity linking and consent. + +### 11.6. Prosumer – Single Rooftop Solar Meter + +Requires DER certification. + +### 11.7. Prosumer – Multiple Meters with Solar + +Multiple program enrollments required. + +### 11.8. Prosumer – EV with V2G + +Requires control rights, telemetry consent, and device capability checks. + +--- + +## 12. Governance and Operational Guidance + +Utilities must: + +* Operate or federate IdP +* Maintain accurate meter and DER registries +* Expose BPP endpoints +* Certify and monitor EAs + +EAs must: + +* Maintain trained staff +* Keep audit trails +* Adhere to data retention and privacy policies + +Network participants must: + +* Use the onboarding SDK +* Not store identity information beyond what is allowed +* Present correct program information + +--- + +## 13. Data Models and Storage Considerations + +Recommended tables: + +* subjects +* subject_utility_links +* meters and meter_subject_links +* ders and der_subject_links +* program_enrollments (VC references) +* consents and consent_events +* audit_logs + +Use encryption, tokenization, and strict retention schedules. + +--- + +## 14. Security and Privacy Implementation + +* Enforce mutual TLS for all service-to-service calls. +* Sign Beckn messages. +* Rotate signing keys. +* Avoid collecting identity attributes beyond what is required. +* Provide consent revocation and logging. + +--- + +## 15. Testing, Certification and Compliance + +Test categories include: + +* Identity login flows +* Multi-meter and multi-site flows +* DER discovery and certification +* Cross-utility onboarding +* Beckn compliance +* VC issuance + +Compliance levels range from basic consumer onboarding to V2G-capable advanced programs. + +--- + +## 16. Deployment Topology Recommendations + +Recommend: + +* Separate identity, BPP, and data layers +* Use API gateway for Beckn traffic +* Deploy BPP close to CIS/MDM for low latency +* Maintain separate environments +* Use centralized logging and monitoring + +Topology diagram: + +```mermaid +graph TD + subgraph DMZ[Edge Layer] + GW[API Gateway] + end + + subgraph APP[Application Layer] + PORTAL[Utility or EA Portals] + SDKSVC[SDK Backend] + BPP[Program Owner BPP] + end + + subgraph CORE[Utility Core Systems] + CIS[CIS] + MDM[MDM] + DERREG[DER Registry] + BILL[Billing] + end + + subgraph IDSYS[Identity and Credentials] + IDP[Identity Provider] + VCISS[VC Issuer / Revocation] + end + + PORTAL --> GW --> BPP + SDKSVC --> GW --> BPP + PORTAL --> IDP + SDKSVC --> IDP + BPP --> CIS + BPP --> MDM + BPP --> DERREG + BPP --> BILL + BPP --> VCISS +``` + +--- + +## 17. Developer Tooling and SDK Recommendations + +* SDK available for JavaScript/TypeScript, Kotlin/Java, Swift, Flutter. +* Include UI modules for consent screens. +* Provide reference apps and API collections. +* Offer sandbox environments for testing. + +--- + +## 18. Appendix A – Sample Payloads + +### 18.1. Init Request + +The init request includes Verifiable Credentials (VCs) provided by the calling entity (Portal/BAP) that prove meter ownership, program eligibility, and DER certifications. + +**Credential Placement:** +- **Meter ownership credentials** are placed in `orderAttributes.meterOwnershipCredential` (single object, not array) +- **Program eligibility and DER certification credentials** are placed in `fulfillmentAttributes.credentials[]` (array) +- **Existing enrollments** for conflict checking are placed in `fulfillmentAttributes.existingEnrollments[]` (array) + +For utilities requiring OTP verification, the `MeterOwnershipCredential` VC is issued by the Utility IdP after successful OTP verification and is included in `orderAttributes`. + +The Program Owner BPP verifies these credentials and checks for conflicts with existing enrollments. + +#### 18.1.1. Example: OTP-Based Init Request + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:00Z", + "message_id": "msg-init-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "mobile": "+919999999999", + "utilityCustomerId": "CUST-123456", + "userType": "CONSUMER" + }, + "customer": { + "name": "Rajesh Kumar" + } + } + } + } +} + +``` +
+ +**Key Fields for OTP Flow**: +- `orderAttributes.userAuth.authMethod`: Set to `"OTP"` +- `orderAttributes.userAuth.mobile`: User's mobile number for OTP delivery + +#### 18.1.2. Example: OAuth2/OIDC-Based Init Request + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:00Z", + "message_id": "msg-init-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwiYXVkIjoicHJvZ3JhbS1vd25lci1icHAiLCJpc3MiOiJodHRwczovL3V0aWxpdHktaWRwLmV4YW1wbGUuY29tIiwiaWF0IjoxNzI5MDAwMDAwLCJleHAiOjE3MjkwMDM2MDB9.signature", + "idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwibmFtZSI6IlJhamVzaCBLdW1hciIsImVtYWlsIjoicmFqZXNoQGV4YW1wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly91dGlsaXR5LWlkcC5leGFtcGxlLmNvbSIsImlhdCI6MTcyOTAwMDAwMCwiZXhwIjoxNzI5MDAzNjAwfQ.signature" + }, + "customer": { + "name": "Rajesh Kumar" + } + } + } + } +} + +``` +
+ +**Key Fields for OAuth2 Flow**: +- `orderAttributes.userAuth.authMethod`: Set to `"OIDC"` +- `orderAttributes.userAuth.accessToken`: OAuth2 access token from Utility IdP +- `orderAttributes.userAuth.idToken`: OIDC identity token (optional) + +#### 18.1.3. Example: Simple Consumer with Single Meter + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:00Z", + "message_id": "msg-init-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING", + "beckn:deliveryAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "customer": { + "name": "Rajesh Kumar", + "email": "rajesh.kumar@example.com" + }, + "meters": [ + { + "meterId": "umid-001", + "utilityId": "utility-example-001" + } + ], + "ders": [] + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "meterOwnershipCredential": { + "credentialId": "vc-meter-ownership-001", + "type": "MeterOwnershipCredential", + "format": "VC-JWT", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiTWV0ZXJPd25lcnNoaXBDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6dXNlci0xMjM0NSIsIm1ldGVySWQiOiJ1bWlkLTAwMSIsInV0aWxpdHlJZCI6InV0aWxpdHktZXhhbXBsZS0wMDEiLCJvd25lcnNoaXBTdGF0dXMiOiJPV05FUiIsInZhbGlkRnJvbSI6IjIwMjQtMDEtMDFUMDA6MDA6MDBaIiwidmFsaWRVbnRpbCI6IjIwMjUtMTItMzFUMjM6NTk6NTlaIn19LCJpc3MiOiJkaWQ6ZXhhbXBsZTp1dGlsaXR5LWNyZWRlbnRpYWwtaXNzdWVyIiwiaWF0IjoxNzA0MDY3MjAwfQ.signature", + "verificationUrl": "https://utility-example-001.com/verify/vc-meter-ownership-001" + } + } + } + } +} + +``` +
+ +**Key Fields**: +- `order.orderAttributes.meterOwnershipCredential`: Meter ownership credential (single object) proving ownership of the meter/CA, verified through OTP flow with Utility IdP + - The credential's `verificationUrl` points to the utility's verification endpoint +- `fulfillment.fulfillmentAttributes.credentials[]`: Array of VCs proving program eligibility, DER certifications, etc. +- `fulfillment.fulfillmentAttributes.existingEnrollments[]`: Array of existing enrollment credentials for conflict checking +- Program Owner BPP verifies these credentials and checks for conflicts + +**Note**: Meter ownership credentials are placed in `orderAttributes` because they are meter-specific attributes tied to the order. Program eligibility and DER certification credentials remain in `fulfillmentAttributes.credentials[]` as they relate to fulfillment requirements. + +#### 18.1.4. Example: Prosumer with Solar and Battery + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T11:00:00Z", + "message_id": "msg-init-prosumer-001", + "transaction_id": "txn-onboard-prosumer-001", + "bap_id": "ea-portal.example.com", + "bap_uri": "https://ea-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-prosumer-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-p2p-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:prosumer-789" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-vpp-p2p-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-prosumer-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING", + "beckn:deliveryAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "meters": [ + { + "meterId": "umid-002", + "utilityId": "utility-example-001" + } + ], + "ders": [ + { + "derId": "der-solar-001", + "type": "SOLAR_PV", + "capacityValue": 10.0, + "capacityUnit": "kW" + }, + { + "derId": "der-battery-001", + "type": "BATTERY_STORAGE", + "capacityValue": 15.0, + "capacityUnit": "kWh" + } + ] + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "mobile": "+919876543210", + "userType": "PROSUMER" + }, + "meterOwnershipCredential": { + "credentialId": "vc-meter-ownership-002", + "type": "MeterOwnershipCredential", + "format": "VC-JWT", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + "verificationUrl": "https://utility-example-001.com/verify/vc-meter-ownership-002" + } + } + } + } +} + +``` +
+ +### 18.2. On_Init Response + +The BPP verifies the provided credentials and checks for conflicts with existing enrollments. The response includes: + +* **`credentialVerification`**: Results of credential verification (status and verified credentials) +* **`conflictCheck`**: Results of conflict checking with existing enrollments +* **`requiredCredentials`**: List of credential types that are required for enrollment (with status indicating if provided) +* **`requiredConsents`**: List of consent types that are required for enrollment (with indication of which are required vs optional) + +The BPP returns either a rejection (with error) or proceeds to confirm. The `requiredCredentials` and `requiredConsents` inform the BAP/Portal what must be collected before the `confirm` request. + +#### 18.2.1. Example: OTP-Based On_Init Response + +When using OTP authentication, the BPP returns an `nguid` (session token) and expiration time. The user must enter the OTP received via SMS. + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "nguid": "LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm", + "message": "OTP sent to +91XXXXXX9999. Valid for 5 minutes.", + "expiresAt": "2024-10-15T10:35:00Z", + "utilityCustomerId": "CUST-123456" + } + } + } + } +} + +``` +
+ +**Key Fields**: +- `orderAttributes.userAuth.nguid`: Session token for OTP verification +- `orderAttributes.userAuth.message`: Human-readable message about OTP delivery +- `orderAttributes.userAuth.expiresAt`: When the OTP expires + +#### 18.2.2. Example: OAuth2/OIDC-Based On_Init Response + +When using OAuth2/OIDC, the BPP validates the token and returns the user's available meters for selection. + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "verified": true, + "verifiedAt": "2024-10-15T10:30:05Z", + "subject": "user-12345", + "issuer": "https://utility-idp.example.com", + "scope": "openid profile email meter:read", + "expiresAt": "2024-10-15T11:30:00Z", + "message": "Token verified successfully" + }, + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "sanctionedLoad": 5.0, + "connectionType": "residential", + "utilityId": "utility-example-001" + }, + { + "meterId": "umid-002", + "meterNumber": "MTR-987654322", + "sanctionedLoad": 10.0, + "connectionType": "commercial", + "utilityId": "utility-example-001" + } + ], + "requiredConsents": [ + { + "type": "DATA_COLLECTION", + "description": "Consent to collect and share meter data for program participation", + "required": true + }, + { + "type": "DER_CONTROL", + "description": "Consent to control DER devices for demand response (if applicable)", + "required": false + } + ] + } + } + } +} + +``` +
+ +**Key Fields**: +- `orderAttributes.userAuth.verified`: Token validation result +- `orderAttributes.userAuth.subject`: User identifier from token +- `orderAttributes.meters[]`: List of meters belonging to the user for selection + +#### 18.2.3. Example: Successful Verification, No Conflicts + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credentialVerification": { + "status": "VERIFIED", + "verifiedCredentials": [ + { + "credentialId": "vc-meter-ownership-001", + "status": "VERIFIED", + "verifiedAt": "2024-10-15T10:30:05Z" + }, + { + "credentialId": "vc-program-eligibility-001", + "status": "VERIFIED", + "verifiedAt": "2024-10-15T10:30:05Z" + } + ] + }, + "conflictCheck": { + "hasConflict": false, + "checkedAt": "2024-10-15T10:30:05Z", + "message": "No conflicts found with existing enrollments" + }, + "requiredCredentials": [ + { + "type": "MeterOwnershipCredential", + "description": "Proof of meter ownership verified through utility OTP verification", + "status": "PROVIDED" + }, + { + "type": "ProgramEligibilityCredential", + "description": "Proof of program eligibility based on meter type and location", + "status": "PROVIDED" + } + ], + "requiredConsents": [ + { + "type": "DATA_COLLECTION", + "description": "Consent to collect and share meter data for program participation", + "required": true + }, + { + "type": "DER_CONTROL", + "description": "Consent to control DER devices for demand response (if applicable)", + "required": false + }, + { + "type": "CROSS_UTILITY_SHARING", + "description": "Consent to share data across utilities (if applicable)", + "required": false + } + ] + } + } + } +} + +``` +
+ +#### 18.2.4. Example: Enrollment Conflict Detected + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-conflict-001", + "transaction_id": "txn-onboard-conflict-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-conflict-001", + "beckn:orderStatus": "REJECTED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credentialVerification": { + "status": "VERIFIED" + }, + "conflictCheck": { + "hasConflict": true, + "conflictingEnrollments": [ + { + "enrollmentId": "enrollment-existing-001", + "programId": "program-flex-other-001", + "conflictReason": "Meter umid-001 is already enrolled in program-flex-other-001 from 2024-09-01 to 2025-09-01", + "conflictType": "METER_ALREADY_ENROLLED" + } + ], + "checkedAt": "2024-10-15T10:30:05Z" + } + } + } + }, + "error": { + "code": "BIZ_ENROLLMENT_CONFLICT", + "message": "Enrollment conflicts with existing enrollment. Meter umid-001 is already enrolled in another program.", + "details": { + "path": "$.message.order.orderAttributes.conflictCheck", + "conflictingEnrollmentId": "enrollment-existing-001", + "conflictEndDate": "2025-09-01T00:00:00Z" + } + } +} + +``` +
+ +### 18.3. Confirm Request + +The confirm request includes the desired enrollment start and end dates, along with any required consents. + +The consents should match the `requiredConsents` specified in the `on_init` response. Each consent indicates: +* `type`: The type of consent (DATA_COLLECTION, DER_CONTROL, CROSS_UTILITY_SHARING) +* `granted`: Boolean indicating if consent was granted +* `grantedAt`: Timestamp when consent was granted +* `description`: Human-readable description of what the consent covers + +#### 18.3.1. Example: OTP-Based Confirm Request + +The confirm request includes the OTP for verification along with the selected meters. + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:33:00Z", + "message_id": "msg-confirm-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "mobile": "+919999999999", + "nguid": "LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm", + "otp": "123456", + "utilityCustomerId": "CUST-123456", + "userType": "CONSUMER" + }, + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z" + } + } + } +} + +``` +
+ +**Key Fields for OTP Flow**: +- `orderAttributes.userAuth.otp`: The OTP entered by the user +- `orderAttributes.userAuth.nguid`: Session token from on_init response +- `orderAttributes.meters[]`: Selected meters for enrollment + +#### 18.3.2. Example: OAuth2/OIDC-Based Confirm Request + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:00Z", + "message_id": "msg-confirm-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwiYXVkIjoicHJvZ3JhbS1vd25lci1icHAiLCJpc3MiOiJodHRwczovL3V0aWxpdHktaWRwLmV4YW1wbGUuY29tIiwiaWF0IjoxNzI5MDAwMDAwLCJleHAiOjE3MjkwMDM2MDB9.signature" + }, + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z" + } + } + } +} + +``` +
+ +**Key Fields for OAuth2 Flow**: +- `orderAttributes.userAuth.accessToken`: OAuth2 access token (for re-validation) +- `orderAttributes.meters[]`: Selected meters from the on_init response + +#### 18.3.3. Example: Confirm with Enrollment Dates + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:00Z", + "message_id": "msg-confirm-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "consents": [ + { + "type": "DATA_COLLECTION", + "granted": true, + "grantedAt": "2024-10-15T10:33:00Z", + "description": "Consent to collect and share meter data for program participation" + }, + { + "type": "DER_CONTROL", + "granted": false, + "description": "Consent to control DER devices for demand response (not applicable for this enrollment)" + } + ] + } + } + } +} + +``` +
+ +### 18.4. On_Confirm Response + +The Program Owner BPP returns a signed Program Enrollment Credential as a Verifiable Credential. **The credential is placed in `fulfillmentAttributes.credential`**, not in `orderAttributes`. The `orderAttributes` contains enrollment metadata (enrollmentId, status, dates, audit logs). + +#### 18.4.1. Example: OTP-Based On_Confirm Response (Success) + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:33:05Z", + "message_id": "msg-on-confirm-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:orderNumber": "ENR-2024-OTP-001234", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "verified": true, + "verifiedAt": "2024-10-15T10:33:05Z", + "message": "OTP verification successful", + "utilityCustomerId": "CUST-123456" + }, + "enrollmentId": "enrollment-otp-001", + "status": "ACTIVE", + "programId": "program-p2p-trading-001", + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "sanctionedLoad": 5.0, + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "enrolledAt": "2024-10-15T10:33:05Z", + "loggedAt": "2024-10-15T10:33:05Z", + "logReference": "log-enrollment-otp-001", + "credential": { + "credentialId": "vc:enrollment:otp-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialUrl": "https://vpp-program-owner.example.com/credentials/vc:enrollment:otp-001", + "verificationUrl": "https://vpp-program-owner.example.com/verify/vc:enrollment:otp-001", + "issuedAt": "2024-10-15T10:33:05Z" + }, + "p2pdetails": { + "usertype": "prosumer", + "isp2pactive": true, + "iscaactive": false, + "meternumber": "MTR-987654321", + "sdload": "5.0", + "cuflimit": "10.0" + } + } + } + } +} + +``` +
+ +**Key Fields**: +- `orderAttributes.userAuth.verified`: Indicates OTP was verified successfully +- `orderAttributes.credential`: The issued Program Enrollment Credential +- `orderAttributes.p2pdetails`: Additional utility-specific details (additionalAttributes) + +#### 18.4.2. Example: OAuth2/OIDC-Based On_Confirm Response (Success) + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:05Z", + "message_id": "msg-on-confirm-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:orderNumber": "ENR-2024-OAUTH-001234", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "verified": true, + "verifiedAt": "2024-10-15T10:35:05Z", + "subject": "user-12345", + "issuer": "https://utility-idp.example.com", + "message": "Token verified successfully" + }, + "enrollmentId": "enrollment-oauth2-001", + "status": "ACTIVE", + "programId": "program-p2p-trading-001", + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "sanctionedLoad": 5.0, + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "enrolledAt": "2024-10-15T10:35:05Z", + "loggedAt": "2024-10-15T10:35:05Z", + "logReference": "log-enrollment-oauth2-001", + "credential": { + "credentialId": "vc:enrollment:oauth2-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialUrl": "https://vpp-program-owner.example.com/credentials/vc:enrollment:oauth2-001", + "verificationUrl": "https://vpp-program-owner.example.com/verify/vc:enrollment:oauth2-001", + "issuedAt": "2024-10-15T10:35:05Z" + }, + "p2pdetails": { + "usertype": "consumer", + "isp2pactive": true, + "iscaactive": false, + "meternumber": "MTR-987654321", + "sdload": "5.0", + "cuflimit": "10.0" + } + } + } + } +} + +``` +
+ +#### 18.4.3. Example: No Meter Specified Error + +When authentication succeeds but no meter is selected, the BPP returns available meters for the user to choose from. + +
Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:05Z", + "message_id": "msg-on-confirm-no-meter-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "FAILED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + } + } + }, + "error": { + "code": "BIZ_NO_METER_SPECIFIED", + "message": "No meter specified for enrollment. Please select from available meters.", + "details": { + "path": "$.message.order.orderAttributes.meters", + "availableMeters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "address": "123 Main Street, Bangalore", + "sanctionedLoad": 5.0, + "connectionType": "residential" + }, + { + "meterId": "umid-002", + "meterNumber": "MTR-987654322", + "address": "456 Oak Avenue, Bangalore", + "sanctionedLoad": 10.0, + "connectionType": "commercial" + } + ] + } + } +} + +``` +
+ +**Key Fields**: +- `error.code`: `BIZ_NO_METER_SPECIFIED` +- `error.details.availableMeters[]`: List of meters the user can select from + +#### 18.4.4. Example: Successful Enrollment with Credential + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:05Z", + "message_id": "msg-on-confirm-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:orderNumber": "ENR-2024-001234", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED", + "beckn:deliveryAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credential": { + "credentialId": "vc:enrollment:consumer-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialUrl": "https://vpp-program-owner.example.com/credentials/vc:enrollment:consumer-001", + "verificationUrl": "https://vpp-program-owner.example.com/verify/vc:enrollment:consumer-001", + "issuedAt": "2024-10-15T10:35:05Z", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUHJvZ3JhbUVucm9sbG1lbnRDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6dXNlci0xMjM0NSIsImVucm9sbG1lbnRJZCI6ImVucm9sbG1lbnQtY29uc3VtZXItMDAxIiwicHJvZ3JhbUlkIjoicHJvZ3JhbS1mbGV4LWRlbWFuZC1yZXNwb25zZS0wMDEiLCJtZXRlcnMiOlsidW1pZC0wMDEiXSwic3RhdHVzIjoiQUNUSVZFIiwic3RhcnREYXRlIjoiMjAyNC0xMS0wMVQwMDowMDowMFoiLCJlbmREYXRlIjoiMjAyNS0xMC0zMVQyMzo1OTo1OVoifSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0xMC0xNVQxMDozNTowNVoiLCJleHBpcmF0aW9uRGF0ZSI6IjIwMjUtMTAtMzFUMjM6NTk6NTlaIn0sImlzcyI6ImRpZDpleGFtcGxlOnZwcC1wcm9ncmFtLW93bmVyIiwiaWF0IjoxNzI5MDk3NzA1fQ.signature" + } + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "enrollmentId": "enrollment-consumer-001", + "status": "ACTIVE", + "programId": "program-flex-demand-response-001", + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "enrolledAt": "2024-10-15T10:35:05Z", + "loggedAt": "2024-10-15T10:35:05Z", + "logReference": "log-enrollment-consumer-001" + } + } + } +} + +``` +
+ +**Key Fields**: +- `orderAttributes.startDate`: When enrollment becomes active +- `orderAttributes.endDate`: When enrollment expires +- `orderAttributes.credential`: Signed Verifiable Credential proving enrollment +- `orderAttributes.loggedAt`: Timestamp when enrollment was logged +- `orderAttributes.logReference`: Reference to enrollment log entry + +### 18.5. Error Response Example + +#### 18.5.1. Example: Credential Verification Failed + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-error-001", + "transaction_id": "txn-onboard-error-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-error-001", + "beckn:orderStatus": "REJECTED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + } + } + }, + "error": { + "code": "SEC_CREDENTIAL_VERIFICATION_FAILED", + "message": "Meter ownership credential could not be verified", + "details": { + "path": "$.message.order.orderAttributes.meterOwnershipCredential", + "credentialId": "vc-meter-ownership-001", + "reason": "Invalid signature or expired credential" + } + } +} + +``` +
+ +**Note**: For vocabulary definitions of new terms and slotted attributes, see `outputs_onboarding_guide/Vocabulary_Definitions.md`. + +### 18.6. Consent Revocation + +Users can revoke consent at any time after enrollment. The revocation uses the Beckn `update` action and updates the W3C VC status list to mark the consent credential as revoked. + +#### 18.6.1. Example: Consent Revocation Request + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T14:30:00Z", + "message_id": "msg-update-consent-revoke-001", + "transaction_id": "txn-revoke-consent-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "updateType": "CONSENT_REVOCATION", + "consentRevocation": { + "consentCredentialId": "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001", + "consentType": "DATA_COLLECTION", + "reason": "USER_REQUESTED", + "revokedAt": "2024-11-20T14:30:00Z", + "effectiveDate": "2024-11-20T14:30:00Z" + } + } + } + } +} + +``` +
+ +**Key Fields**: +- `orderAttributes.updateType`: Set to `CONSENT_REVOCATION` +- `orderAttributes.consentRevocation.consentCredentialId`: ID of the consent VC to revoke +- `orderAttributes.consentRevocation.consentType`: Type of consent being revoked +- `orderAttributes.consentRevocation.reason`: Reason for revocation + +#### 18.6.2. Example: Consent Revocation Response + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T14:30:05Z", + "message_id": "msg-on-update-consent-revoke-001", + "transaction_id": "txn-revoke-consent-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "enrollmentId": "enrollment-consumer-001", + "status": "ACTIVE", + "updateType": "CONSENT_REVOCATION", + "consentRevocation": { + "consentCredentialId": "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001", + "status": "REVOKED", + "revokedAt": "2024-11-20T14:30:05Z", + "statusListUrl": "https://vpp-program-owner.example.com/status/consent-list", + "statusListIndex": "94567", + "message": "Consent has been revoked and added to revocation status list. Future verifications will fail." + } + } + } + } +} + +``` +
+ +**Key Fields**: +- `orderAttributes.consentRevocation.status`: `REVOKED` when processed +- `orderAttributes.consentRevocation.statusListUrl`: URL of the W3C VC status list +- `orderAttributes.consentRevocation.statusListIndex`: Index in the status list +- Verifiers check this status list to verify if consent is still valid + +### 18.7. Unenrollment + +Users can unenroll from a program at any time. Unenrollment revokes the enrollment credential and optionally all associated consent credentials. + +#### 18.7.1. Example: Unenrollment Request + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T15:00:00Z", + "message_id": "msg-update-unenroll-001", + "transaction_id": "txn-unenroll-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "updateType": "UNENROLLMENT", + "unenrollment": { + "enrollmentId": "enrollment-consumer-001", + "reason": "USER_REQUESTED", + "effectiveDate": "2024-11-20T15:00:00Z", + "revokeAllConsents": true + } + } + } + } +} + +``` +
+ +**Key Fields**: +- `orderAttributes.updateType`: Set to `UNENROLLMENT` +- `orderAttributes.unenrollment.enrollmentId`: ID of the enrollment to cancel +- `orderAttributes.unenrollment.revokeAllConsents`: Whether to revoke all associated consents +- `orderAttributes.unenrollment.effectiveDate`: When the unenrollment becomes effective + +#### 18.7.2. Example: Unenrollment Response + +
+Example json :rocket: + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T15:00:05Z", + "message_id": "msg-on-update-unenroll-001", + "transaction_id": "txn-unenroll-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CANCELLED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CANCELLED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "enrollmentId": "enrollment-consumer-001", + "status": "CANCELLED", + "updateType": "UNENROLLMENT", + "unenrollment": { + "enrollmentId": "enrollment-consumer-001", + "status": "CANCELLED", + "cancelledAt": "2024-11-20T15:00:05Z", + "enrollmentCredentialStatus": { + "statusListUrl": "https://vpp-program-owner.example.com/status/enrollment-list", + "statusListIndex": "12345", + "revoked": true + }, + "consentsRevoked": [ + { + "consentCredentialId": "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001", + "statusListUrl": "https://vpp-program-owner.example.com/status/consent-list", + "statusListIndex": "94567", + "revoked": true + } + ], + "message": "Enrollment and all associated consents have been revoked. Enrollment credential and consent credentials have been added to revocation status lists." + }, + "loggedAt": "2024-11-20T15:00:05Z", + "logReference": "log-unenrollment-consumer-001" + } + } + } +} + +``` +
+ +**Key Fields**: +- `order.status`: Set to `CANCELLED` +- `orderAttributes.status`: Set to `CANCELLED` +- `orderAttributes.unenrollment.enrollmentCredentialStatus`: Status list details for enrollment VC revocation +- `orderAttributes.unenrollment.consentsRevoked[]`: Array of revoked consent credentials with their status list details +- All credentials are added to W3C VC status lists for verification + +**Revocation Mechanism**: +- BPP updates W3C VC status lists (BitstringStatusList) to mark credentials as revoked +- Verifiers check status lists before accepting credentials +- Status lists use bitstrings for efficient and privacy-preserving revocation checks + +--- + +## 19. Appendix B – Multi-Utility Interaction Patterns + +For cross-utility enrollments (e.g., BTM devices connected to a different utility), the BPP orchestrates authentication with multiple Utility IdPs: + +```mermaid +sequenceDiagram + participant User + participant BAP as UtilityPortal/BAP + participant BPP as Program Owner BPP + participant IDP_A as Utility A IdP + participant IDP_B as Utility B IdP + + Note over User,IDP_B: Cross-Utility OTP Authentication + User->>BAP: Start cross-utility onboarding
(mobile A, mobile B) + + BAP->>BPP: POST /init
orderAttributes.userAuth: {
authMethod: "OTP",
mobile: "+91-A-number"
} + + BPP->>IDP_A: generateOTP(mobile A) + IDP_A->>User: SMS OTP to mobile A + IDP_A-->>BPP: { nguid_A } + + BPP-->>BAP: /on_init { nguid_A, message: "OTP sent to Utility A" } + + User->>BAP: Enter OTP A + BAP->>BPP: POST /confirm (partial)
{ userAuth: { otp_A }, secondaryAuth: { mobile_B } } + + BPP->>IDP_A: verifyOTP(mobile A, otp A) + IDP_A-->>BPP: { verified, meters_A, p2pdetails_A } + + BPP->>IDP_B: generateOTP(mobile B) + IDP_B->>User: SMS OTP to mobile B + IDP_B-->>BPP: { nguid_B } + + BPP-->>BAP: /on_confirm (partial)
{ userAuth_A: verified, nguid_B } + + User->>BAP: Enter OTP B + BAP->>BPP: POST /confirm (final)
{ meters: [...], otp_B } + + BPP->>IDP_B: verifyOTP(mobile B, otp B) + IDP_B-->>BPP: { verified, meters_B, p2pdetails_B } + + BPP->>BPP: Create cross-utility enrollment + BPP-->>BAP: /on_confirm
{ enrollmentId, credential,
additionalAttributes: { p2pdetails_A, p2pdetails_B } } + + BAP-->>User: Cross-utility enrollment successful +``` + +**Note:** The exact multi-utility flow may vary based on implementation. Some utilities may support OAuth2/OIDC tokens instead of OTP. The BPP is responsible for orchestrating authentication with each utility's IdP. + +--- + +## 20. Appendix C – Error Handling Patterns + +Error codes use a three-letter prefix to indicate the error layer: + +| Prefix | Layer | Description | +|--------|-------|-------------| +| `SEC_` | Security | Authentication/authorization failures | +| `BIZ_` | Business | Business rule violations | +| `NET_` | Network | Communication/connectivity issues | +| `SYS_` | System | Internal system errors | + +**Authentication Errors (SEC_):** +* `SEC_OTP_INVALID` - OTP verification failed +* `SEC_OTP_EXPIRED` - OTP/nguid has expired +* `SEC_TOKEN_INVALID` - OAuth2/OIDC token validation failed +* `SEC_TOKEN_EXPIRED` - OAuth2/OIDC token has expired +* `SEC_CREDENTIAL_VERIFICATION_FAILED` - Verifiable Credential validation failed + +**Business Errors (BIZ_):** +* `BIZ_NO_METER_SPECIFIED` - No meter provided in confirm request +* `BIZ_METER_NOT_FOUND` - Specified meter not found in utility system +* `BIZ_ENROLLMENT_CONFLICT` - Meter already enrolled in conflicting program +* `BIZ_DER_NOT_CERTIFIED` - DER certification missing or invalid +* `BIZ_PROGRAM_NOT_AVAILABLE` - Program not available for this meter/utility +* `BIZ_CROSS_UTILITY_CONSENT_REQUIRED` - Cross-utility consent needed +* `BIZ_EA_NOT_CERTIFIED` - Enrollment Agency not certified + +**Example Error Responses:** + +```json +// Authentication Error +{ + "error": { + "code": "SEC_OTP_INVALID", + "message": "OTP verification failed. Please check the OTP and try again.", + "details": { + "path": "$.message.order.orderAttributes.userAuth.otp" + } + } +} +``` + +```json +// No Meter Specified - includes available meters for selection +{ + "error": { + "code": "BIZ_NO_METER_SPECIFIED", + "message": "No meter specified for enrollment. Please select from available meters.", + "details": { + "path": "$.message.order.orderAttributes.meters", + "availableMeters": [ + { "meterId": "umid-001", "meterNumber": "MTR-001", "sanctionedLoad": 5.0 }, + { "meterId": "umid-002", "meterNumber": "MTR-002", "sanctionedLoad": 10.0 } + ] + } + } +} +``` + +Each error must follow Beckn's standard error object structure with `code`, `message`, and optional `details`. The `details.availableMeters` field allows BAP to display user's meters for selection on retry. diff --git a/docs/implementation-guides/v2/P2P_Trading/P2P_Trading_implementation_guide_DRAFT.md b/docs/implementation-guides/v2/P2P_Trading/P2P_Trading_implementation_guide_DRAFT.md index 0a96512c..091859f1 100644 --- a/docs/implementation-guides/v2/P2P_Trading/P2P_Trading_implementation_guide_DRAFT.md +++ b/docs/implementation-guides/v2/P2P_Trading/P2P_Trading_implementation_guide_DRAFT.md @@ -1,8 +1,6 @@ # P2P Energy Trading Implementation Guide -## Overview - -This implementation guide provides comprehensive instructions for implementing Peer-to-Peer (P2P) Energy Trading using Beckn Protocol v2 with composable schemas. This guide covers all transaction flows, field mappings, best practices, and migration from v1. +Version 0.1 (Non-Normative) ## Table of Contents @@ -11,24 +9,11 @@ This implementation guide provides comprehensive instructions for implementing P - [3. Intended Audience](#3-intended-audience) - [4. Conventions and Terminology](#4-conventions-and-terminology) - [5. Terminology](#5-terminology) -- [6. Mechanics of a P2P energy transaction flow](#6-mechanics-of-a-p2p-energy-transaction-flow) +- [6. Example User Journey](#6-example-user-journey) + - [6.1. Sequence diagram of a P2P transaction](#61-sequence-diagram-of-a-p2p-transaction) - [7. Reference Architecture](#7-reference-architecture) - [7.1. Architecture Diagram](#71-architecture-diagram) - [7.2. Actors](#72-actors) - - [7.3. Beckn Protocol v2 for Energy Trading](#73-beckn-protocol-v2-for-energy-trading) - - [7.4. Schema Overview](#74-schema-overview) - - [7.4.1. EnergyResource (Item.itemAttributes)](#741-energyresource-itemitemattributes) - - [7.4.2. EnergyTradeOffer (Offer.offerAttributes)](#742-energytradeoffer-offerofferattributes) - - [7.4.3. EnergyTradeContract (Order.orderAttributes)](#743-energytradecontract-orderorderattributes) - - [7.4.4. EnergyTradeDelivery (Fulfillment.attributes)](#744-energytradedelivery-fulfillmentattributes) - - [7.5. v2 Composable Schema Architecture](#75-v2-composable-schema-architecture) - - [7.5.1. Schema Composition Points](#751-schema-composition-points) - - [7.6. Implementation Notes](#76-implementation-notes) - - [7.6.1. Key Differences from v1](#761-key-differences-from-v1) - - [7.6.1.1. Discover/Search Request](#7611-discoversearch-request) - - [7.6.1.2. Item Attributes](#7612-item-attributes) - - [7.6.1.3. Order Attributes](#7613-order-attributes) - - [7.6.1.4. Fulfillment Stops](#7614-fulfillment-stops) - [8. Creating an Open Network for Peer to Peer Energy Trading](#8-creating-an-open-network-for-peer-to-peer-energy-trading) - [8.1. Setting up a Registry](#81-setting-up-a-registry) - [8.1.1. For a Network Participant](#811-for-a-network-participant) @@ -45,38 +30,34 @@ This implementation guide provides comprehensive instructions for implementing P - [8.2.1. Installing Beckn ONIX](#821-installing-beckn-onix) - [8.2.2. Configuring Beckn ONIX for Peer to Peer Energy Trading](#822-configuring-beckn-onix-for-peer-to-peer-energy-trading) - [8.2.3. 10.2.3 Performing a test transaction](#823-1023-performing-a-test-transaction) -- [9. Transaction Flows](#9-transaction-flows) - - [9.1. Discover Flow](#91-discover-flow) - - [9.2. Select Flow](#92-select-flow) - - [9.3. Init Flow](#93-init-flow) - - [9.4. Confirm Flow](#94-confirm-flow) - - [9.4.1. Cascaded Init Example (Utility Registration)](#941-cascaded-init-example-utility-registration) - - [9.5. Confirm Flow](#95-confirm-flow) - - [9.6. Status Flow](#96-status-flow) -- [10. Field Mapping Reference](#10-field-mapping-reference) - - [10.1. v1 to v2 Field Mapping](#101-v1-to-v2-field-mapping) - - [10.2. Meter ID Format Migration](#102-meter-id-format-migration) -- [11. Integration Patterns](#11-integration-patterns) - - [11.1. Attaching Attributes to Core Objects](#111-attaching-attributes-to-core-objects) - - [11.2. JSON-LD Context Usage](#112-json-ld-context-usage) - - [11.3. Discovery Filtering](#113-discovery-filtering) -- [12. Best Practices](#12-best-practices) - - [12.1. Discovery Optimization](#121-discovery-optimization) - - [12.2. Meter ID Handling](#122-meter-id-handling) - - [12.3. Settlement Cycle Management](#123-settlement-cycle-management) - - [12.4. Meter Readings](#124-meter-readings) - - [12.5. Telemetry Data](#125-telemetry-data) - - [12.6. Error Handling](#126-error-handling) -- [13. Migration from v1](#13-migration-from-v1) - - [13.1. Key Changes](#131-key-changes) - - [13.2. Migration Checklist](#132-migration-checklist) - - [13.3. Example Migration](#133-example-migration) -- [14. Examples](#14-examples) - - [14.1. Complete Examples](#141-complete-examples) - - [14.2. Example Scenarios](#142-example-scenarios) - - [14.3. Inter energy retailer P2P trading](#143-inter-energy-retailer-p2p-trading) -- [15. Additional Resources](#15-additional-resources) -- [16. Support](#16-support) +- [9. Schema overview](#9-schema-overview) + - [9.1. v2 Composable Schema Architecture](#91-v2-composable-schema-architecture) + - [9.2. Schema Composition Points](#92-schema-composition-points) + - [9.3. EnergyResource (Item.itemAttributes)](#93-energyresource-itemitemattributes) + - [9.4. EnergyTradeOffer (Offer.offerAttributes)](#94-energytradeoffer-offerofferattributes) + - [9.5. EnergyTradeContract (Order.orderAttributes)](#95-energytradecontract-orderorderattributes) + - [9.6. EnergyOrderItem (OrderItem.orderItemAttributes)](#96-energyorderitem-orderitemorderitemattributes) + - [9.7. EnergyTradeDelivery (EnergyOrderItem.fulfillmentAttributes)](#97-energytradedelivery-energyorderitemfulfillmentattributes) +- [10. API Reference \& examples](#10-api-reference--examples) + - [10.1. Discover flow](#101-discover-flow) + - [10.2. Select Flow](#102-select-flow) + - [10.3. Init Flow](#103-init-flow) + - [10.4. Confirm Flow](#104-confirm-flow) + - [10.4.1. Cascaded Init Example (Utility Registration)](#1041-cascaded-init-example-utility-registration) + - [10.5. Confirm Flow](#105-confirm-flow) + - [10.5.1. Cascaded Confirm Example (Utility Trade Logging)](#1051-cascaded-confirm-example-utility-trade-logging) + - [10.6. Status Flow](#106-status-flow) + - [10.6.1. Curtailed Trade Status](#1061-curtailed-trade-status) + - [10.7. Update Flow (Provider-Initiated)](#107-update-flow-provider-initiated) + - [10.7.1. Utility-Initiated Trade Curtailment](#1071-utility-initiated-trade-curtailment) +- [11. Additional Resources](#11-additional-resources) + - [11.1. Inter energy retailer P2P trading](#111-inter-energy-retailer-p2p-trading) +- [12. Additional Resources](#12-additional-resources) + - [12.0.1. **Integrating with your software**](#1201-integrating-with-your-software) + - [12.0.1.1. **Integrating the BAP**](#12011-integrating-the-bap) + - [12.0.1.2. **Integrating the BPP**](#12012-integrating-the-bpp) + - [12.1. FAQs](#121-faqs) + - [12.2. References](#122-references) Table of contents and section auto-numbering was done using [Markdown-All-In-One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) vscode extension. Specifically `Markdown All in One: Create Table of Contents` and `Markdown All in One: Add/Update section numbers` commands accessible via vs code command pallete. @@ -96,32 +77,9 @@ This document provides an implementation guidance for deploying peer to peer (P2 services using the Beckn Protocol ecosystem. Peer to peer energy trading enables energy producers (prosumers) to directly sell excess energy to consumers. -- Utilities enable such decentralized energy exchange in order to encourage local balancing of - supply & demand, reduce transmission losses, congestion and promote the green energy. -- It can boost the demand when the supply is abundent, say during mid-day solar or nightly wind, - because consumers may find a lower price in a marketplace than the price of importing from utility. -- It could also boost renewable energy supply if producers discover a higher price for it than the utility - export price. -- It can reduce losses for the grid operator if they are obligated to buy back the surplus energy - at a fixed rate which could be higher than the spot price, during solar hours. It also unlocks - new revenue streams for the grid operator as they have full visibility to and can charge - wheeling charges for any peer to peer energy trade happening on their transmission lines. -- Finally, it can increase the cash in-flows for a large prosumer who has accumulated large - credit with the utility due to net-metering policies, but cannot redeem it for cash. -- This achieves beneficial outcomes for producer, consumer and the utility (and in turn redces bills - for other consumers not participating in the trade.) -- Such P2P trade is virtual (non-binding) in the sense that it is made before the delivery hour and is - based on best estimate of load & generation, but the real energy flows may deviate - from the trade contract. But the incentive of a better revenue by - adhereing to the contracted energy flows as well as the cost of deviation cited in contract, - naturally aligns incentives of consumers & producers to deliver the contracted energy flows. -- Each P2P trade contract references a real or a virtual meter, against which the deviations are measured post-facto. - Utility may keep track of the sanctioned (maximum allowed) load or generation at each meter and can limit - the amount of energy trades via a network policy. Physical meters belong to prosumers. - Virtual meters may belong to aggregators and have zero power flows during delivery. - Such aggregators can establish peer to peer relationship - with many producers and consumers and balance pre-delivery supply & demand, since any deviation of net trade - flow away from zero (real power flowing through virtual meter) will be penalized. +Peer-to-peer (P2P) energy trading enables decentralized energy exchange that benefits all participants while strengthening the grid. For consumers, P2P markets offer lower prices during periods of abundant renewable supply (such as mid-day solar or nightly wind), creating demand for supply that might otherwise be curtailed. For producers, these markets may provide higher prices incentivizing the renewable energy generation. Grid operators benefit through reduced transmission losses, local supply-demand balancing, and new revenue streams from wheeling charges on P2P transactions. Additionally, prosumers with accumulated net-metering credits can monetize them through P2P trades, converting credits into cash. These benefits extend beyond direct participants, as reduced grid congestion and improved efficiency ultimately lower costs for all ratepayers. + +P2P trades are executed virtually before the delivery hour based on estimated load and generation, with actual energy flows potentially deviating from contracts. However, the economic incentives, namely better revenue for adhering to contracts and penalties for deviations, naturally align producer and consumer behavior toward delivering contracted energy. Each trade contract references a real or virtual meter for post-delivery deviation measurement, with utilities maintaining visibility and control through network policies that limit trade volumes based on sanctioned load or generation at each meter. Virtual meters enable aggregators to balance supply and demand across multiple participants, as any net deviation from zero flow through these virtual meters incurs penalties, creating a self-regulating mechanism for grid stability. --- @@ -131,7 +89,7 @@ services using the Beckn Protocol ecosystem. Peer to peer energy trading enables * Discovery of energy trading partners. * Some recommendations for BAPs, BPPs and NFOs on how to map protocol API calls to internal systems (or vice-versa). -* Session management and billing coordination between Beckn and OCPI protocols +* Session management and billing coordination between BAP, BPP and the utility BPP. This document does NOT cover: @@ -141,14 +99,15 @@ This document does NOT cover: and apportion the shortfall against it. * Cyber-security and best practices to ensure privacy of market participants by guarding of personally identifiable information data. -* Escrow services to cover the cost trade participant reneging or defaulting on payment. +* Payment guarantees or ACH hold until fulfillment to cover the cost trade participant reneging or defaulting on payment. # 3. Intended Audience -* Consumer Application Developers (BAPs). -* Technology Integrators: Building bridges between existing beckn v1 P2P trading infrastructure and new Beckn v2 based marketplaces -* Business Stakeholders: Understanding technical capabilities and implementation requirements for peer to pee trading strategies -* Standards Organizations: Evaluating interoperability approaches for future energy trading standards development +* Energy Trading Platforms: Platforms that want to participate in P2P trading on behalf of prosumers and consumers +* Technology Integrators: Technology providers building adaptors between existing DERs and applications +* System Architects: Designing scalable, interoperable P2P trading ecosystems +* Business Stakeholders: Understanding technical capabilities and implementation requirements for P2P marketplace strategies +* Standards Organizations: Evaluating interoperability approaches for future P2P standards development # 4. Conventions and Terminology @@ -161,63 +120,99 @@ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "S | BAP | Beckn Application Platform | Consumer-facing application that initiates transactions. | | BPP | Beckn Provider Platform | Service provider platform that responds to BAP requests. | | NFO | Network Facilitator Organization | Organization responsible for the adoption and growth of the network. Usually the custodian of the network’s registry. | -| CDS | Catalog Discovery Service | Enables discovery of energy services from BPPs in the network. | +| CDS | Catalog Discovery Service | Enables discovery of energy services from BPPs in the network by providing a cache service for catalogs. | +| MDMS | Meter Data Management System | Platform that enables collection, storage and processing of smart meter data | +| RMS | Revenue Management System | Platform that enables money flows throughout the transaction and post fulfillment | + + +# 6. Example User Journey + +This walkthrough demonstrates a complete P2P energy trading transaction: + +Nisha, who has a large rooftop solar is hoping to get better returns than 3 INR/kwh for the surplus energy mid-day and wants to sell it at 6 INR/kwh. She is eligible to participate and is enrolled as a prosumer in a peer to peer trading app (BPP), which publishes the offer to catalog discovery service (CDS). + +In parallel, nearby, Swati runs a small mill which has a sanctioned load of 20kw. Anticipating large seasonal demand, she is looking to purchase cheaper energy than the utility import price of of 10 INR/kwh between 10am to 6pm for next week. Swati is eligible to participate and is already enrolled as a consumer on a *different* peer to peer energy trading app (BAP), and declares her intent to buy with above price and time of day filters. + +To her delight, the Beckn network helps her *discovers* Nisha's offer of renewable energy at 6 INR/kwh between 12am to 4pm on all days in that week. With wheeling charges of 1 INR/kwh, the total 8 INR/kwh is still 20% cheaper than importing. -> Note: -> This document does not detail the mapping between Beckn Protocol and OCPI. Please refer to [this](../../v1-EOS/DEG00x_Mapping-OCPI-and-Beckn-Protocol-for-EV-Charging-Interoperability.md) document for the same. -> BPPs are NOT aggregators. Any CPO that has implemented a Beckn Protocol endpoint is a BPP. -> For all sense and purposes, CPOs are essentially BPPs and eMSPs are essentially BAPs. +She *initiates* in an order of 20kw. The (BAP) app knows and shares her meter number with the seller's app (BPP), which in turn shares both with the utility BPP which knows the sanctioned import & export for each meter and existing trades. Utility BPP applies a 50% cap policy and replies back saying that upto 10kw of trade is allowed and adds wheeling charges to the quote. It also adds terms & conditions that specify that any underconsumption by Swati will be treated as a spot export by her reimbursed at 3 INR/kwh and any underproduction by solar farm by the farm is treated as a spot import at 10$/kwh. After this Swati *confirms* the 8 INR/kwh final order with her BAP, solar farm BPP in turn cascaded it to utility BPP and utility BPP acknowledges, locks and logs the trade and deducts it from the further trading allowance in those hours for both Swati & Nisha. -# 6. Mechanics of a P2P energy transaction flow +On the delivery day, the floor mill is busy and consumes 400 kwh from the rooftop solar and saves on its +in energy costs. The solar farm gains additional revenue, and utility gets revenue for the upkeep of transmission & to cover the administration cost. Utility BPP sends the final settlement including the wheeling and deviation charges to Swati & the solar farm. Swati pays the solar farm BPP +for the trade itself via her BAP. -This walkthrough demonstrates a complete P2P energy trading transaction: a consumer purchases -10 kWh of solar energy from a producer for grid injection delivery. +## 6.1. Sequence diagram of a P2P transaction + +**Scenario**: Consumer (BAP: `bap.energy-consumer.com`) buys 10 kWh from Producer (BPP: `bpp.energy-provider.com`) on Oct 4, 2025, 10:00 AM - 6:00 PM. Source meter: `100200300`, Target meter: `98765456`. Transaction ID: `txn-energy-001`. -**Scenario**: Consumer (BAP: `bap.energy-consumer.com`) buys 10 kWh from Producer (BPP: `bpp.energy-provider.com`) on Oct 4, 2024, 10:00 AM - 6:00 PM. Source meter: `100200300`, Target meter: `98765456`. Transaction ID: `txn-energy-001`. ```mermaid sequenceDiagram - participant BAP as P2P Trading BAP - participant BPP as P2P Trading BPP - participant Utility as Transmission BPP (Utility) - - Note over BAP, BPP: Standard Init Flow - BAP->>BPP: /init (Initialize Order) - - Note over BPP, Utility: Cascaded Init to Utility - BPP->>Utility: /init (Register Trade & Check Load) - - Note right of Utility: 1. Verify Sanctioned Load
2. Calculate Wheeling Charges - - Utility->>BPP: /on_init (Quote with Wheeling Charges) - - BAP->>BPP: 6. /status (Final check) - BPP-->>BAP: Delivery COMPLETED, 10.0 kWh, SETTLED + participant P2P Trading BAP + participant CDS + participant P2P Trading BPP + participant Utility Company + P2P Trading BPP-->>CDS: upload(Item/Offer changes) + Note over P2P Trading BAP, Utility Company: Opening Bell + P2P Trading BAP->>+CDS: discover + CDS-->>-P2P Trading BAP: on_discover + Note over P2P Trading BAP, P2P Trading BPP: Post-discovery, BAP calls BPP directly for transaction APIs + P2P Trading BAP->>+P2P Trading BPP: select + P2P Trading BPP-->>-P2P Trading BAP: on_select + + P2P Trading BAP->>+P2P Trading BPP: init (Trading Order) + P2P Trading BPP->>+Utility Company: cascaded init (Initialze a delivery order) + Note right of Utility Company: 1. Calculate wheeling charges
2. remaining trading limit + Utility Company-->>-P2P Trading BPP: on_init (Wheeling charges, remaining trading limit etc. ) + P2P Trading BPP-->>-P2P Trading BAP: cascaded_on_init + + P2P Trading BAP->>+P2P Trading BPP: confirm (Trading Order) + P2P Trading BPP->>+Utility Company: cascaded confirm (Initialize a delivery order) + Note right of Utility Company: 1. Log trade
2. Deduct from trading limits. + Utility Company-->>-P2P Trading BPP: on_confirm (remaining trading limit etc. ) + P2P Trading BPP-->>-P2P Trading BAP: on_confirm (Trading Order) + Note over P2P Trading BAP, Utility Company: Closing Bell + + Note over P2P Trading BAP, Utility Company: Fulfillment + Utility Company->> Utility Company: Calculate total actual energy
surplus produced by provider + alt if total produced energy is less than total traded + Utility Company->> Utility Company: Calculate penalty charges
(Will be adjusted in the provider's monthly bill) + else if total produced energy is more than total traded + Utility Company->> Utility Company: Calculate amount to be paid to provider
(Total Surplus - Total Traded ) X Grid buying rate" + end + Utility Company->> Utility Company: Apportion total actual energy
produced in proportion to
energy promised across all trades
on that day before closing bell + loop Send on_update to each consumer(P2P Trading BPP) containing updated order details + Utility Company->>+P2P Trading BPP: on_update (updated Delivery Order details) + end + loop Send cascaded on_update to each P2P Trading BAP containing updated order details + P2P Trading BPP->>+P2P Trading BAP: cascaded on_update (updated Delivery Order details) + end ``` **1. Discover** - Consumer searches for solar energy with JSONPath filters (`sourceType == 'SOLAR'`, `deliveryMode == 'GRID_INJECTION'`, `availableQuantity >= 10.0`). -Request: [discover-request.json](../../../../examples/v2/P2P_Trading/discover-request.json) | Response: [discover-response.json](../../../../examples/v2/P2P_Trading/discover-response.json) +Request: [discover-request.json](../../../../examples/p2p-trading/v2/discover-request.json) | Response: [discover-response.json](../../../../examples/p2p-trading/v2/discover-response.json) *Result: Found `energy-resource-solar-001` at $0.15/kWh, 30.5 kWh available* **2. Select** - Consumer selects item and receives quote breakdown. -Request: [select-request.json](../../../../examples/v2/P2P_Trading/select-request.json) | Response: [select-response.json](../../../../examples/v2/P2P_Trading/select-response.json) +Request: [select-request.json](../../../../examples/p2p-trading/v2/select-request.json) | Response: [select-response.json](../../../../examples/p2p-trading/v2/select-response.json) *Result: Quote $4.00 ($1.50 energy + $2.50 wheeling)* **3. Init** - Consumer provides meter IDs (`100200300` → `98765456`), time window, and payment details. BPP may cascade to Utility for load verification and wheeling charges. -Request: [init-request.json](../../../../examples/v2/P2P_Trading/init-request.json) | Response: [init-response.json](../../../../examples/v2/P2P_Trading/init-response.json) -Cascaded Flow: [cascaded-init-request.json](../../../../examples/v2/P2P_Trading/cascaded-init-request.json) | [cascaded-on-init-response.json](../../../../examples/v2/P2P_Trading/cascaded-on-init-response.json) -*Result: Order initialized, contract PENDING* +Request: [init-request.json](../../../../examples/p2p-trading/v2/init-request.json) | Response: [init-response.json](../../../../examples/p2p-trading/v2/init-response.json) +Cascaded Flow: [cascaded-init-request.json](../../../../examples/p2p-trading/v2/cascaded-init-request.json) | [cascaded-on-init-response.json](../../../../examples/p2p-trading/v2/cascaded-on-init-response.json) +*Result: Order initialized, contract PENDING. Utility BPP responds with wheeling charges in `orderValue.components` and remaining trading limits in `orderAttributes.remainingTradingLimit`.* -**4. Confirm** - Consumer confirms order to activate contract. -Request: [confirm-request.json](../../../../examples/v2/P2P_Trading/confirm-request.json) | Response: [confirm-response.json](../../../../examples/v2/P2P_Trading/confirm-response.json) -*Result: Contract ACTIVE, settlement cycle `settle-2024-10-04-001` created* +**4. Confirm** - Consumer confirms order to activate contract. BPP may cascade to Utility to log the trade and deduct from trading limits. +Request: [confirm-request.json](../../../../examples/p2p-trading/v2/confirm-request.json) | Response: [confirm-response.json](../../../../examples/p2p-trading/v2/confirm-response.json) +Cascaded Flow: [cascaded-confirm-request.json](../../../../examples/p2p-trading/v2/cascaded-confirm-request.json) | [cascaded-on-confirm-response.json](../../../../examples/p2p-trading/v2/cascaded-on-confirm-response.json) +*Result: Contract ACTIVE, settlement cycle `settle-2024-10-04-001` created. Utility BPP logs trade and responds with updated remaining trading limits in `orderAttributes.remainingTradingLimit`.* **5. Status (In Progress)** - Consumer monitors delivery progress. BPP updates meter readings and telemetry every 15-30 minutes. -Request: [status-request.json](../../../../examples/v2/P2P_Trading/status-request.json) | Response: [status-response.json](../../../../examples/v2/P2P_Trading/status-response.json) +Request: [status-request.json](../../../../examples/p2p-trading/v2/status-request.json) | Response: [status-response.json](../../../../examples/p2p-trading/v2/status-response.json) *Result: Delivery IN_PROGRESS, 9.8 kWh delivered (98%), real-time telemetry* **6. Status (Completed)** - Consumer checks final status after delivery completion. -Response: [status-response-completed.json](../../../../examples/v2/P2P_Trading/status-response-completed.json) +Response: [status-response-completed.json](../../../../examples/p2p-trading/v2/status-response-completed.json) *Result: Delivery COMPLETED, 10.0 kWh delivered, settlement SETTLED ($4.00)* **Summary**: Transaction completed in ~8.5 hours. 10.0 kWh delivered. Total cost $4.00. Daily settlement cycle processed. @@ -229,20 +224,138 @@ The section defines the reference ecosystem architecture that is used for buildi ## 7.1. Architecture Diagram -![](../assets/beckn-one-deg-arch.png) + +TBD ## 7.2. Actors -1. Beckn One Global Root Registry -2. Beckn One Catalog Discovery Service -3. Beckn Application Platforms -4. Beckn Provider Platforms -5. Peer to Peer trading Registry +1. Prosumers and consumers with smart meters. +2. Beckn One Global Root Registry +3. Beckn One Catalog Discovery Service +4. Beckn Application Platforms +5. Beckn Provider Platforms +6. Peer to Peer trading Registry + +TODO: Explain the role of each entity in detail for P2P trading, and whether they are required or optional and API interface to them. + + +# 8. Creating an Open Network for Peer to Peer Energy Trading + +TODO: move this section into a seperate `../core_spec/` folder, and reference from there in implementation guides of EV charging, P2P tradig etc. + +To create an open network for energy trading requires all the producers, prosumers and consumers BAPs, BPPs, to be able to discover each other and become part of a common club. This club is manifested in the form of a Registry maintained by an NFO. + +## 8.1. Setting up a Registry + +The NP Registry serves as the root of addressability and trust for all network participants. It maintains comprehensive details such as the participant’s globally unique identifier (ID), network address (Beckn API URL), public key, operational domains, and assigned role (e.g., BAP, BPP, CDS). In addition to managing participant registration, authentication, authorization, and permission control, the Registry oversees participant verification, activation, and overall lifecycle management, ensuring that only validated and authorized entities can operate within the network. + +![](../assets/registry-arch.png) + +You can publish your registries at [DeDi.global](https://publish.dedi.global/). + +### 8.1.1. For a Network Participant + +#### 8.1.1.1. Step 1 : Claiming a Namespace + +To get started, any platform that has implemented Beckn Protocol MUST create a globally unique namespace for themselves. +All NPs (BAPs, BPPs, CDS’es) **MUST** register as a user on dedi.global and claim a unique namespace against their FQDN to become globally addressable. As part of the claiming process, the user must prove ownership of the namespace by verifying the ownership of their domain. Namespace would be at an organisation level. You can put your organisation name as the name of the namespace. + +#### 8.1.1.2. Step 2 : Setting up a Registry + +Once the namespace is claimed, each NP **MUST** create a Beckn NP registry in the namespace to list their subscriber details. While creating the registry, the user **MUST** configure it with the [subscriber schema](https://gist.githubusercontent.com/nirmalnr/a6e5b17522169ecea4f3ccdd831af7e4/raw/7744f2542034db9675901b61b41c8228ea239074/beckn-subscriber-no-refs.schema.json). Example of a registry name can be `subscription-details`. + +#### 8.1.1.3. Step 3 : Publishing subscriber details + +In the registry that is created, NPs **MUST** publish their subscription details including their ID, network endpoints, public keys, operational domains and assigned roles (BAP, BPP) as records. + +*Detailed steps to create namespaces and registries in dedi.global can be found [here](https://github.com/dedi-global/docs/blob/0976607aabc6641d330a3d41a3bd89ab8790ea09/user-guides/namespace%20and%20registry%20creation.md).* + +### 8.1.2. Step 4 : Share details of the registry created with the Beckn One team + +Once the registry is created and details are published, the namespace and the registry name of the newly created registry should be shared with the beckn one team. + +### 8.1.3. For a Network facilitator organization + +#### 8.1.3.1. Step 1 : Claiming a Namespace + +An NFO **MAY** register as a user on dedi.global and claim a unique namespace against their FQDN. As part of the claiming process, the user must prove ownership of that namespace by verifying the ownership of that domain. The NFO name can be set as the name of the namespace. +*Note: A calibrated roll out of this infrastructure is planned and hence before it is open to the general public NFOs are advised to share their own domain and the domains of their NPs to the Beckn One team so that they can be whitelisted which will allow the NPs to verify the same using TXT records in their DNS.* + +#### 8.1.3.2. Step 2 : Setting up a Registry + +Network facilitators **MAY** create registries under their own namespace using the [subscriber reference schema](https://gist.githubusercontent.com/nirmalnr/a6e5b17522169ecea4f3ccdd831af7e4/raw/b7cf8a47e6531ef22744b43e6305b8d8cc106e7b/beckn-subscriber-reference.schema.json) to point to either whole registries or records created by the NPs in their own namespaces. Example of a registry name can be `subscription-details`. + +#### 8.1.3.3. Step 3 : Publishing subscriber details + +In the registry that is created, NFOs **MAY** publish records which act as pointers to either whole registries or records created by the NPs records. The URL field in the record would be the lookup URL for a registry or a record as per DeDi protocol. + +Example: For referencing another registry created by an NP, the record details created would be: + +```json +{ + "url": "https://.dedi.global/dedi/lookup/example-company/subscription-details", + "type": "Registry", + "subscriber_id": "example-company.com" +} +``` + +Here `example-company` is the namespace of the NP, and all records added in the registry is referenced here. + +If only one record in the registry needs to be referenced, then the record details created would be: + +```json +{ + "url": "https://.dedi.global/dedi/lookup/example-company/subscription-details/energy-bap", + "type": "Record", + "subscriber_id": "example-company.com" +} +``` + +Here `energy-bap` is the name of the record created by the NP in this registry. Only that record is referenced here. + +*Detailed steps to create namespaces and registries in dedi.global can be found [here](https://github.com/dedi-global/docs/blob/0976607aabc6641d330a3d41a3bd89ab8790ea09/user-guides/namespace%20and%20registry%20creation.md).* + +#### 8.1.3.4. Step 4 : Share details of the registry created with the Beckn One team + +Once the registry is created and details are published, the namespace and the registry name of the newly created registry should be shared with the beckn one team. + +## 8.2. Setting up the Protocol Endpoints + +This section contains instructions to set up and test the protocol stack for transactions. + +### 8.2.1. Installing Beckn ONIX + +All NPs SHOULD install the Beckn ONIX adapter to quickly get set up and become Beckn Protocol compliant. Click [here](https://github.com/Beckn-One/beckn-onix?tab=readme-ov-file#automated-setup-recommended)) to learn how to set up Beckn ONIX. + +### 8.2.2. Configuring Beckn ONIX for Peer to Peer Energy Trading + +A detailed Configuration Guide is available [here](https://github.com/Beckn-One/beckn-onix/blob/main/CONFIG.md). A quick read of key concepts from the link is recommended. + +Specifically, please use the following configuration: +1. Configure dediregistry plugin instead of registry plugin. Read more [here](https://github.com/Beckn-One/beckn-onix/tree/main/pkg/plugin/implementation/dediregistry). +2. Start with using Simplekeymanager plugin during development, read more [here](https://github.com/Beckn-One/beckn-onix/tree/main/pkg/plugin/implementation/simplekeymanager). For production deployment, you may setup vault. +3. For routing calls to Catalog Discovery Service, refer to routing configuration [here](https://github.com/Beckn-One/beckn-onix/blob/main/config/local-simple-routing-BAPCaller.yaml). + +### 8.2.3. 10.2.3 Performing a test transaction + +Step 1 : Download the postman collection, from [here](/testnet/p2p-trading-devkit/postman). + +Step 2 : Run API calls + +If you are a BAP + +1. Configure the collection/environment variables to the newly installed Beckn ONIX adapter URL and other variables in the collection. +2. Select the discover example and hit send +3. You should see the service catalog response + +If you are a BPP ----- +1. Configure the collection/environment variables to the newly installed Beckn ONIX adapter URL and other variables in the collection. +2. Select the on_status example and hit send +3. You should see the response in your console -## 7.3. Beckn Protocol v2 for Energy Trading +# 9. Schema overview Beckn Protocol v2 provides a composable schema architecture that enables: - **Modular Attribute Bundles**: Energy-specific attributes attached to core Beckn objects @@ -250,9 +363,35 @@ Beckn Protocol v2 provides a composable schema architecture that enables: - **Standards Alignment**: Integration with IEEE 2030.5 (mRID), OCPP, OCPI - **Flexible Discovery**: Meter-based discovery and filtering -## 7.4. Schema Overview +## 9.1. v2 Composable Schema Architecture + +``` +┌─────────────────────────────────────────────────────────┐ +│ Core Beckn Objects │ +│ Item | Offer | Order | Fulfillment | Provider │ +└─────────────────────────────────────────────────────────┘ + │ + │ Attach Attributes + ▼ +┌─────────────────────────────────────────────────────────┐ +│ Energy* Attribute Bundles │ +│ EnergyResource | EnergyTradeOffer | EnergyTradeContract │ +│ EnergyTradeDelivery │ +└─────────────────────────────────────────────────────────┘ +``` + +## 9.2. Schema Composition Points + +| Attribute Bundle | Attach To | Purpose | +| ----------------------- | ------------------------ | ---------------------------------------------------------------------------------- | +| **EnergyResource** | `Item.itemAttributes` | Energy source characteristics (source type, delivery mode, meter ID, availability) | +| **EnergyTradeOffer** | `Offer.offerAttributes` | Pricing models, settlement types, wheeling charges, validity windows | +| **EnergyTradeContract** | `Order.orderAttributes` | Contract status, meter IDs, settlement cycles, billing cycles | +| **EnergyOrderItem** | `OrderItem.orderItemAttributes` | Wrapper containing customerAttributes and optional fulfillmentAttributes | +| **EnergyTradeDelivery** | `EnergyOrderItem.fulfillmentAttributes` | Per-orderItem delivery status, meter readings with time windows, energy allocation | + -### 7.4.1. EnergyResource (Item.itemAttributes) +## 9.3. EnergyResource (Item.itemAttributes) **Purpose**: Describes tradable energy resources @@ -267,7 +406,7 @@ Beckn Protocol v2 provides a composable schema architecture that enables: **Example**: ```json { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyResource/v0.2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/EnergyResource/v0.2/context.jsonld", "@type": "EnergyResource", "sourceType": "SOLAR", "deliveryMode": "GRID_INJECTION", @@ -280,7 +419,7 @@ Beckn Protocol v2 provides a composable schema architecture that enables: } ``` -### 7.4.2. EnergyTradeOffer (Offer.offerAttributes) +## 9.4. EnergyTradeOffer (Offer.offerAttributes) **Purpose**: Defines pricing and settlement terms for energy trades @@ -295,7 +434,7 @@ Beckn Protocol v2 provides a composable schema architecture that enables: **Example**: ```json { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/EnergyTradeOffer/v0.2/context.jsonld", "@type": "EnergyTradeOffer", "pricingModel": "PER_KWH", "settlementType": "DAILY", @@ -309,7 +448,7 @@ Beckn Protocol v2 provides a composable schema architecture that enables: } ``` -### 7.4.3. EnergyTradeContract (Order.orderAttributes) +## 9.5. EnergyTradeContract (Order.orderAttributes) **Purpose**: Tracks commercial agreements and contract lifecycle @@ -325,7 +464,7 @@ Beckn Protocol v2 provides a composable schema architecture that enables: **Example**: ```json { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/EnergyTradeContract/v0.2/context.jsonld", "@type": "EnergyTradeContract", "contractStatus": "ACTIVE", "sourceMeterId": "100200300", @@ -336,447 +475,183 @@ Beckn Protocol v2 provides a composable schema architecture that enables: } ``` -### 7.4.4. EnergyTradeDelivery (Fulfillment.attributes) +## 9.6. EnergyOrderItem (OrderItem.orderItemAttributes) -**Purpose**: Tracks physical energy transfer and delivery status +**Purpose**: Wrapper schema for per-orderItem attributes containing customer information and optional fulfillment tracking + +**Location**: `beckn:orderItemAttributes` **Key Attributes**: -- `deliveryStatus`: PENDING, IN_PROGRESS, COMPLETED, FAILED -- `deliveryMode`: EV_CHARGING, BATTERY_SWAP, V2G, GRID_INJECTION -- `deliveredQuantity`: Quantity delivered in kWh -- `meterReadings`: Array of meter readings (source, target, energy flow) -- `telemetry`: Energy flow telemetry (ENERGY, POWER, VOLTAGE, etc.) -- `settlementCycleId`: Link to settlement cycle +- `customerAttributes`: Contains EnergyCustomer schema with customer meter and utility info (always required) +- `fulfillmentAttributes`: Contains EnergyTradeDelivery schema with delivery tracking (only in on_status/on_update) **Example**: ```json { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeDelivery/v0.2/context.jsonld", - "@type": "EnergyTradeDelivery", - "deliveryStatus": "IN_PROGRESS", - "deliveryMode": "GRID_INJECTION", - "deliveredQuantity": 9.8, - "meterReadings": [ - { - "timestamp": "2024-10-04T12:00:00Z", - "sourceReading": 1000.5, - "targetReading": 990.3, - "energyFlow": 10.2 + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "customerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 7.5, + "meterReadings": [...], + "lastUpdated": "2024-10-04T15:00:00Z" } - ], - "telemetry": [...] + } } ``` +## 9.7. EnergyTradeDelivery (EnergyOrderItem.fulfillmentAttributes) -## 7.5. v2 Composable Schema Architecture +**Purpose**: Tracks physical energy transfer and delivery status per orderItem -``` -┌─────────────────────────────────────────────────────────┐ -│ Core Beckn Objects │ -│ Item | Offer | Order | Fulfillment | Provider │ -└─────────────────────────────────────────────────────────┘ - │ - │ Attach Attributes - ▼ -┌─────────────────────────────────────────────────────────┐ -│ Energy* Attribute Bundles │ -│ EnergyResource | EnergyTradeOffer | EnergyTradeContract │ -│ EnergyTradeDelivery │ -└─────────────────────────────────────────────────────────┘ -``` +**Location**: Nested within `beckn:orderItemAttributes.fulfillmentAttributes` (not at top-level Order) -### 7.5.1. Schema Composition Points +**When Populated**: Only in `on_status` and `on_update` responses. NOT present in init/confirm flows. -| Attribute Bundle | Attach To | Purpose | -| ----------------------- | ------------------------ | ---------------------------------------------------------------------------------- | -| **EnergyResource** | `Item.itemAttributes` | Energy source characteristics (source type, delivery mode, meter ID, availability) | -| **EnergyTradeOffer** | `Offer.offerAttributes` | Pricing models, settlement types, wheeling charges, validity windows | -| **EnergyTradeContract** | `Order.orderAttributes` | Contract status, meter IDs, settlement cycles, billing cycles | -| **EnergyTradeDelivery** | `Fulfillment.attributes` | Delivery status, meter readings, telemetry, settlement linkage | +**Key Attributes**: +- `deliveryStatus`: PENDING, IN_PROGRESS, COMPLETED, FAILED +- `deliveryMode`: EV_CHARGING, BATTERY_SWAP, V2G, GRID_INJECTION +- `deliveredQuantity`: Total quantity delivered so far in kWh +- `meterReadings`: Array of meter readings with time windows (see below) +- `curtailedQuantity`: Optional, quantity curtailed from contract (kWh) +- `curtailmentReason`: Optional, reason code (GRID_OUTAGE, EMERGENCY, CONGESTION, MAINTENANCE, OTHER) +- `lastUpdated`: UTC timestamp of last update -## 7.6. Implementation Notes +**Meter Readings Structure** (IEC 61968/ESPI compliant): +```json +{ + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "deliveredEnergy": 0.0, // Energy TO customer (imported from grid) - ESPI flowDirection=1 + "receivedEnergy": 7.5, // Energy FROM customer (exported to grid) - ESPI flowDirection=19 + "allocatedEnergy": 7.5, // Net energy allocated for this trade + "unit": "kWh" +} +``` -**For BAP Implementers**: -1. **Discovery**: Use JSONPath filters to search by energy attributes (sourceType, deliveryMode, availableQuantity, productionWindow) -2. **Order Management**: Track order state through PENDING → ACTIVE → COMPLETED -3. **Status Polling**: Poll status endpoint every 15-30 minutes during active delivery -4. **Error Handling**: Handle cases where delivery fails or quantities don't match -5. **Settlement**: Monitor settlement cycle status for payment processing +**Example** (within EnergyOrderItem.fulfillmentAttributes): +```json +{ + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "customerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 7.5, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "deliveredEnergy": 0.0, + "receivedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T15:00:00Z" + } + } +} +``` -**For BPP Implementers**: -1. **Catalog Management**: Keep catalog updated with available energy and accurate production windows -2. **Meter Readings**: Update meter readings regularly during delivery (every 15-30 minutes) -3. **Telemetry**: Provide real-time telemetry data for monitoring -4. **Settlement**: Calculate settlement amounts based on delivered quantity and pricing model -5. **State Management**: Properly transition contract and delivery statuses +**Note**: Top-level `beckn:fulfillment` is no longer used for energy delivery tracking. Each orderItem tracks its own fulfillment independently via `fulfillmentAttributes`. -**Common Patterns**: -- **Idempotency**: Use transaction_id consistently across all requests -- **Time Windows**: Validate production windows and trade time windows -- **Meter IDs**: Always use IEEE mRID format (plain numeric ID, not `der://` format) -- **Quantity Validation**: Ensure delivered quantity matches contracted quantity (within tolerance) +# 10. API Reference & examples -### 7.6.1. Key Differences from v1 +## 10.1. Discover flow -| Aspect | v1 (Layer2) | v2 (Composable) | -| ---------------------- | ------------------- | ---------------------------- | -| **Schema Extension** | `allOf` in paths | Composable attribute bundles | -| **Attribute Location** | `Item.attributes.*` | `Item.itemAttributes.*` | -| **Meter Format** | `der://meter/{id}` | IEEE 2030.5 mRID `{id}` | -| **JSON-LD** | Not used | Full JSON-LD support | -| **Modularity** | Monolithic | Modular bundles | +**Purpose**: Search for available energy resources +**Endpoint**: `POST /discover` -For developers familiar with v1, here's a quick mapping guide: +**v1 to v2 Mapping**: +- v1 `message.intent.item.quantity.selected.measure` → v2 `message.filters.expression` (JSONPath filter on `availableQuantity`) +- v1 `message.intent.fulfillment.stops[].time.range.start` → v2 `message.filters.expression` (JSONPath filter on `productionWindow.start`) +- v1 `message.intent.fulfillment.stops[].time.range.end` → v2 `message.filters.expression` (JSONPath filter on `productionWindow.end`) +- **Note**: v2 does not support `intent` object. All search parameters are expressed via JSONPath filters. -#### 7.6.1.1. Discover/Search Request +
+Request Example -**v1 Format**: ```json { - "message": { - "intent": { - "item": { - "quantity": { - "selected": { - "measure": { - "value": "10", - "unit": "kWH" - } - } - } + "context": { + "version": "2.0.0", + "action": "discover", + "timestamp": "2024-10-04T10:00:00Z", + "message_id": "msg-discover-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0", + "location": { + "city": { + "code": "BLR", + "name": "Bangalore" }, - "fulfillment": { - "stops": [{ - "type": "end", - "location": { - "address": "der://uppcl.meter/98765456" - }, - "time": { - "range": { - "start": "2024-10-04T10:00:00", - "end": "2024-10-04T18:00:00" - } - } - }] + "country": { + "code": "IND", + "name": "India" } - } - } -} -``` - -**v2 Format** (No intent object - uses JSONPath filters): -```json -{ + }, + "schema_context": [ + "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld" + ] + }, "message": { - "text_search": "solar energy grid injection", "filters": { "type": "jsonpath", - "expression": "$[?(@.itemAttributes.sourceType == 'SOLAR' && @.itemAttributes.deliveryMode == 'GRID_INJECTION' && @.itemAttributes.availableQuantity >= 10.0 && @.itemAttributes.productionWindow.start <= '2024-10-04T10:00:00Z' && @.itemAttributes.productionWindow.end >= '2024-10-04T18:00:00Z')]" + "expression": "$[?('p2p-trading-pilot-network' == @.beckn:networkId && @.beckn:itemAttributes.sourceType == 'SOLAR' && @.beckn:itemAttributes.deliveryMode == 'GRID_INJECTION' && @.beckn:itemAttributes.availableQuantity >= 10.0 )]" } } } -``` -**Changes**: -- ❌ **Removed**: `intent` object is not supported in v2 discover API -- ✅ **Quantity**: v1 `intent.item.quantity.selected.measure.value` → v2 `filters.expression` with `availableQuantity >= 10.0` -- ✅ **Time Range**: v1 `intent.fulfillment.stops[].time.range` → v2 `filters.expression` with `productionWindow.start <= '...' && productionWindow.end >= '...'` -- ✅ **All Parameters**: Expressed via JSONPath filters in v2 +``` +
-#### 7.6.1.2. Item Attributes +
Immediate successful Response -**v1 Format**: ```json { - "Item": { - "attributes": { - "sourceType": "SOLAR", - "meterId": "der://meter/100200300", - "availableQuantity": 30.5 - } - } + "ack_status": "ACK", + "timestamp": "2025-10-14T07:31:05Z" } ``` +
+ + +
+Async Response Example: `on_discover` -**v2 Format**: -```json -{ - "@type": "beckn:Item", - "beckn:itemAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyResource/v0.2/context.jsonld", - "@type": "EnergyResource", - "sourceType": "SOLAR", - "meterId": "100200300", - "availableQuantity": 30.5 - } -} -``` - -**Changes**: -- ⚠️ Path: `Item.attributes.*` → `beckn:itemAttributes.*` -- ⚠️ Meter format: `der://meter/100200300` → `100200300` -- ➕ Add `@context` and `@type` for JSON-LD - -#### 7.6.1.3. Order Attributes - -**v1 Format**: -```json -{ - "Order": { - "attributes": { - "sourceMeterId": "der://pge.meter/100200300", - "targetMeterId": "der://ssf.meter/98765456", - "contractStatus": "ACTIVE" - } - } -} -``` - -**v2 Format**: -```json -{ - "@type": "beckn:Order", - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "contractStatus": "ACTIVE" - } -} -``` - -**Changes**: -- ⚠️ Path: `Order.attributes.*` → `beckn:orderAttributes.*` -- ⚠️ Meter format: `der://pge.meter/100200300` → `100200300` -- ➕ Add `@context` and `@type` for JSON-LD - -#### 7.6.1.4. Fulfillment Stops - -**v1 Format**: -```json -{ - "Fulfillment": { - "stops": [{ - "type": "start", - "location": { - "address": "der://uppcl.meter/92982739" - } - }, { - "type": "end", - "location": { - "address": "der://uppcl.meter/98765456" - } - }] - } -} -``` - -**v2 Format**: -```json -{ - "@type": "beckn:Fulfillment", - "beckn:stops": [{ - "@type": "beckn:Stop", - "beckn:type": "START", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "92982739" - } - }, { - "@type": "beckn:Stop", - "beckn:type": "END", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "98765456" - } - }] -} -``` - -**Changes**: -- ⚠️ Meter format: `der://uppcl.meter/92982739` → `92982739` -- ⚠️ Type case: `"start"` → `"START"`, `"end"` → `"END"` -- ➕ Add `@type` for JSON-LD - - - -# 8. Creating an Open Network for Peer to Peer Energy Trading - -To create an open network for energy trading requires all the producers, prosumers and consumers BAPs, BPPs, to be able to discover each other and become part of a common club. This club is manifested in the form of a Registry maintained by an NFO. - -## 8.1. Setting up a Registry - -The NP Registry serves as the root of addressability and trust for all network participants. It maintains comprehensive details such as the participant’s globally unique identifier (ID), network address (Beckn API URL), public key, operational domains, and assigned role (e.g., BAP, BPP, CDS). In addition to managing participant registration, authentication, authorization, and permission control, the Registry oversees participant verification, activation, and overall lifecycle management, ensuring that only validated and authorized entities can operate within the network. - -![](../assets/registry-arch.png) - -You can publish your registries at [DeDi.global](https://publish.dedi.global/). - -### 8.1.1. For a Network Participant - -#### 8.1.1.1. Step 1 : Claiming a Namespace - -To get started, any platform that has implemented Beckn Protocol MUST create a globally unique namespace for themselves. -All NPs (BAPs, BPPs, CDS’es) **MUST** register as a user on dedi.global and claim a unique namespace against their FQDN to become globally addressable. As part of the claiming process, the user must prove ownership of the namespace by verifying the ownership of their domain. Namespace would be at an organisation level. You can put your organisation name as the name of the namespace. - -#### 8.1.1.2. Step 2 : Setting up a Registry - -Once the namespace is claimed, each NP **MUST** create a Beckn NP registry in the namespace to list their subscriber details. While creating the registry, the user **MUST** configure it with the [subscriber schema](https://gist.githubusercontent.com/nirmalnr/a6e5b17522169ecea4f3ccdd831af7e4/raw/7744f2542034db9675901b61b41c8228ea239074/beckn-subscriber-no-refs.schema.json). Example of a registry name can be `subscription-details`. - -#### 8.1.1.3. Step 3 : Publishing subscriber details - -In the registry that is created, NPs **MUST** publish their subscription details including their ID, network endpoints, public keys, operational domains and assigned roles (BAP, BPP) as records. - -*Detailed steps to create namespaces and registries in dedi.global can be found [here](https://github.com/dedi-global/docs/blob/0976607aabc6641d330a3d41a3bd89ab8790ea09/user-guides/namespace%20and%20registry%20creation.md).* - -### 8.1.2. Step 4 : Share details of the registry created with the Beckn One team - -Once the registry is created and details are published, the namespace and the registry name of the newly created registry should be shared with the beckn one team. - -### 8.1.3. For a Network facilitator organization - -#### 8.1.3.1. Step 1 : Claiming a Namespace - -An NFO **MAY** register as a user on dedi.global and claim a unique namespace against their FQDN. As part of the claiming process, the user must prove ownership of that namespace by verifying the ownership of that domain. The NFO name can be set as the name of the namespace. -*Note: A calibrated roll out of this infrastructure is planned and hence before it is open to the general public NFOs are advised to share their own domain and the domains of their NPs to the Beckn One team so that they can be whitelisted which will allow the NPs to verify the same using TXT records in their DNS.* - -#### 8.1.3.2. Step 2 : Setting up a Registry - -Network facilitators **MAY** create registries under their own namespace using the [subscriber reference schema](https://gist.githubusercontent.com/nirmalnr/a6e5b17522169ecea4f3ccdd831af7e4/raw/b7cf8a47e6531ef22744b43e6305b8d8cc106e7b/beckn-subscriber-reference.schema.json) to point to either whole registries or records created by the NPs in their own namespaces. Example of a registry name can be `subscription-details`. - -#### 8.1.3.3. Step 3 : Publishing subscriber details - -In the registry that is created, NFOs **MAY** publish records which act as pointers to either whole registries or records created by the NPs records. The URL field in the record would be the lookup URL for a registry or a record as per DeDi protocol. - -Example: For referencing another registry created by an NP, the record details created would be: - -```json -{ - "url": "https://.dedi.global/dedi/lookup/example-company/subscription-details", - "type": "Registry", - "subscriber_id": "example-company.com" -} -``` - -Here `example-company` is the namespace of the NP, and all records added in the registry is referenced here. - -If only one record in the registry needs to be referenced, then the record details created would be: - -```json -{ - "url": "https://.dedi.global/dedi/lookup/example-company/subscription-details/energy-bap", - "type": "Record", - "subscriber_id": "example-company.com" -} -``` - -Here `energy-bap` is the name of the record created by the NP in this registry. Only that record is referenced here. - -*Detailed steps to create namespaces and registries in dedi.global can be found [here](https://github.com/dedi-global/docs/blob/0976607aabc6641d330a3d41a3bd89ab8790ea09/user-guides/namespace%20and%20registry%20creation.md).* - -#### 8.1.3.4. Step 4 : Share details of the registry created with the Beckn One team - -Once the registry is created and details are published, the namespace and the registry name of the newly created registry should be shared with the beckn one team. - -## 8.2. Setting up the Protocol Endpoints - -This section contains instructions to set up and test the protocol stack for transactions. - -### 8.2.1. Installing Beckn ONIX - -All NPs SHOULD install the Beckn ONIX adapter to quickly get set up and become Beckn Protocol compliant. Click [here](https://github.com/Beckn-One/beckn-onix?tab=readme-ov-file#automated-setup-recommended)) to learn how to set up Beckn ONIX. - -### 8.2.2. Configuring Beckn ONIX for Peer to Peer Energy Trading - -A detailed Configuration Guide is available [here](https://github.com/Beckn-One/beckn-onix/blob/main/CONFIG.md). A quick read of key concepts from the link is recommended. - -Specifically, please use the following configuration: -1. Configure dediregistry plugin instead of registry plugin. Read more [here](https://github.com/Beckn-One/beckn-onix/tree/main/pkg/plugin/implementation/dediregistry). -2. Start with using Simplekeymanager plugin during development, read more [here](https://github.com/Beckn-One/beckn-onix/tree/main/pkg/plugin/implementation/simplekeymanager). For production deployment, you may setup vault. -3. For routing calls to Catalog Discovery Service, refer to routing configuration [here](https://github.com/Beckn-One/beckn-onix/blob/main/config/local-simple-routing-BAPCaller.yaml). - -### 8.2.3. 10.2.3 Performing a test transaction - -Step 1 : Download the postman collection, from [here](/testnet/postman-collections/v2/P2P_Trading). - -Step 2 : Run API calls - -If you are a BAP - -1. Configure the collection/environment variables to the newly installed Beckn ONIX adapter URL and other variables in the collection. -2. Select the discover example and hit send -3. You should see the service catalog response - -If you are a BPP - -1. Configure the collection/environment variables to the newly installed Beckn ONIX adapter URL and other variables in the collection. -2. Select the on_status example and hit send -3. You should see the response in your console - ---- - -# 9. Transaction Flows - -## 9.1. Discover Flow - -**Purpose**: Search for available energy resources - -**Endpoint**: `POST /discover` - -**v1 to v2 Mapping**: -- v1 `message.intent.item.quantity.selected.measure` → v2 `message.filters.expression` (JSONPath filter on `availableQuantity`) -- v1 `message.intent.fulfillment.stops[].time.range.start` → v2 `message.filters.expression` (JSONPath filter on `productionWindow.start`) -- v1 `message.intent.fulfillment.stops[].time.range.end` → v2 `message.filters.expression` (JSONPath filter on `productionWindow.end`) -- **Note**: v2 does not support `intent` object. All search parameters are expressed via JSONPath filters. - -
-Request Example - -```json -{ - "context": { - "version": "2.0.0", - "action": "discover", - "timestamp": "2024-10-04T10:00:00Z", - "message_id": "msg-discover-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade", - "location": { - "city": { - "code": "BLR", - "name": "Bangalore" - }, - "country": { - "code": "IND", - "name": "India" - } - } - }, - "message": { - "text_search": "solar energy grid injection", - "filters": { - "type": "jsonpath", - "expression": "$[?(@.itemAttributes.sourceType == 'SOLAR' && @.itemAttributes.deliveryMode == 'GRID_INJECTION' && @.itemAttributes.availableQuantity >= 10.0 && @.itemAttributes.productionWindow.start <= '2024-10-04T10:00:00Z' && @.itemAttributes.productionWindow.end >= '2024-10-04T18:00:00Z')]" - } - } -} - - -``` -
- -
-Response Example - ```json { "context": { @@ -790,46 +665,53 @@ If you are a BPP "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "catalogs": [ { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Catalog", "beckn:id": "catalog-energy-001", + "beckn:bppId": "bpp.energy-provider.com", + "beckn:bppUri": "https://bpp.energy-provider.com", "beckn:descriptor": { "@type": "beckn:Descriptor", "schema:name": "Solar Energy Trading Catalog" }, "beckn:items": [ { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Item", + "beckn:networkId": ["p2p-trading-pilot-network"], + "beckn:isActive": true, "beckn:id": "energy-resource-solar-001", "beckn:descriptor": { "@type": "beckn:Descriptor", - "schema:name": "Solar Energy - 30.5 kWh", - "beckn:shortDesc": "Carbon Offset Certified Solar Energy", - "beckn:longDesc": "High-quality solar energy from verified source with carbon offset certification" + "schema:name": "Solar Energy - 30.5 kWh" }, "beckn:provider": { - "@type": "beckn:Provider", - "beckn:id": "provider-solar-farm-001" + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + } }, "beckn:itemAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyResource/v0.2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld", "@type": "EnergyResource", "sourceType": "SOLAR", "deliveryMode": "GRID_INJECTION", "certificationStatus": "Carbon Offset Certified", - "meterId": "100200300", - "inverterId": "inv-12345", + "meterId": "der://meter/100200300", "availableQuantity": 30.5, - "productionWindow": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - }, + "productionWindow": [ + { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T10:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + ], "sourceVerification": { "verified": true, "verificationDate": "2024-09-01T00:00:00Z", @@ -843,26 +725,70 @@ If you are a BPP ], "beckn:offers": [ { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Offer", - "beckn:id": "offer-energy-001", + "beckn:id": "offer-morning-001", "beckn:descriptor": { "@type": "beckn:Descriptor", - "schema:name": "Daily Settlement Solar Energy Offer" + "schema:name": "Morning Solar Energy Offer - 6am-12pm" }, "beckn:provider": "provider-solar-farm-001", - "beckn:items": ["energy-resource-solar-001"], - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 0.15, - "schema:priceCurrency": "USD", - "schema:unitText": "kWh" + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "wheelingCharges": { + "amount": 2.5, + "currency": "USD", + "description": "PG&E Grid Services wheeling charge" + }, + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T23:59:59Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer - 12pm-6pm" }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], "beckn:offerAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", "@type": "EnergyTradeOffer", "pricingModel": "PER_KWH", "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", "wheelingCharges": { "amount": 2.5, "currency": "USD", @@ -871,8 +797,24 @@ If you are a BPP "minimumQuantity": 1.0, "maximumQuantity": 100.0, "validityWindow": { - "start": "2024-10-04T00:00:00Z", - "end": "2024-10-04T23:59:59Z" + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T23:59:59Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" } } } @@ -882,7 +824,6 @@ If you are a BPP } } - ```
@@ -895,14 +836,14 @@ If you are a BPP - **JSONPath Filters**: Use JSONPath filters to search by `itemAttributes.sourceType`, `itemAttributes.deliveryMode`, `itemAttributes.availableQuantity`, and `itemAttributes.productionWindow` - **Response**: Includes full Item with EnergyResource attributes and Offer with EnergyTradeOffer attributes -## 9.2. Select Flow +## 10.2. Select Flow **Purpose**: Select items and offers to build an order **Endpoint**: `POST /select`
-Request Example +Request Example ```json { @@ -917,40 +858,165 @@ If you are a BPP "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - } - } - } -} - - + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } + } +} + +``` +
+ +
Immediate successful Response + +```json +{ + "ack_status": "ACK", + "timestamp": "2025-10-14T07:31:05Z" +} ```
-Response Example +Asynchronous Response Example: `on_select` ```json { @@ -965,64 +1031,150 @@ If you are a BPP "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:quote": { - "@type": "beckn:Quotation", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 1.5, - "schema:priceCurrency": "USD", - "schema:unitText": "kWh" }, - "beckn:breakup": [ - { - "@type": "beckn:Breakup", - "beckn:title": "Energy Cost (10 kWh @ $0.15/kWh)", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 1.5, - "schema:priceCurrency": "USD" + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" } }, - { - "@type": "beckn:Breakup", - "beckn:title": "Wheeling Charges", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 2.5, - "schema:priceCurrency": "USD" + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } } } - ] - } + } + ] } } } - ```
@@ -1031,7 +1183,7 @@ If you are a BPP - Select offers by `beckn:id` - Response includes priced quote with breakup -## 9.3. Init Flow +## 10.3. Init Flow **Purpose**: Initialize order with fulfillment and payment details @@ -1043,7 +1195,7 @@ If you are a BPP - v1 `Order.attributes.*` → v2 `Order.orderAttributes.*` (path change)
-Request Example +Request Example ```json { @@ -1058,96 +1210,171 @@ If you are a BPP "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" }, - "beckn:fulfillments": [ + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:stops": [ - { - "@type": "beckn:Stop", - "beckn:id": "stop-start-001", - "beckn:type": "START", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "100200300" - }, - "beckn:time": { - "@type": "beckn:Time", - "beckn:range": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - } - } + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" }, - { - "@type": "beckn:Stop", - "beckn:id": "stop-end-001", - "beckn:type": "END", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "98765456" - }, - "beckn:time": { - "@type": "beckn:Time", - "beckn:range": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - } + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" } } - ] - } - ], - "beckn:payments": [ + } + }, { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } } ], - "beckn:billing": { - "@type": "beckn:Billing", - "beckn:name": "Energy Consumer", - "beckn:email": "consumer@example.com", - "beckn:phone": "+1-555-0100" + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" } } } } +``` +
+ +
Immediate successful Response +```json +{ + "ack_status": "ACK", + "timestamp": "2025-10-14T07:31:05Z" +} ```
-Response Example +Asynchronous Response Example: `on_init` ```json { @@ -1162,89 +1389,156 @@ If you are a BPP "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 }, - "beckn:fulfillments": [ + "beckn:orderItems": [ { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:stops": [ - { - "@type": "beckn:Stop", - "beckn:id": "stop-start-001", - "beckn:type": "START", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "100200300" - } + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" }, - { - "@type": "beckn:Stop", - "beckn:id": "stop-end-001", - "beckn:type": "END", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "98765456" + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" } } - ] - } - ], - "beckn:payments": [ + } + }, { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } } ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "PENDING", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "inverterId": "inv-12345", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR", - "certification": { - "status": "Carbon Offset Certified", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - } + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" } } } } - ```
@@ -1254,237 +1548,263 @@ If you are a BPP - **Meter IDs**: Use IEEE mRID format (`"100200300"`) instead of v1's `der://` format (`"der://pge.meter/100200300"`) - **Response**: Includes EnergyTradeContract attributes with PENDING status -## 9.4. Confirm Flow +## 10.4. Confirm Flow **Purpose**: Confirm and activate the order **Endpoint**: `POST /confirm` -### 9.4.1. Cascaded Init Example (Utility Registration) +### 10.4.1. Cascaded Init Example (Utility Registration) This flow demonstrates the cascaded `/init` call from the P2P Trading BPP to the Utility Company (Transmission BPP) to register the trade and calculate wheeling charges. +**Request Flow**: P2P Trading BPP sends a cascaded `init` request to the Utility BPP with the order details (items, offers, fulfillments, payments). + +**Response Flow**: Utility BPP responds with `on_init` containing: +- **Wheeling charges**: Provided in `orderValue` with breakdown in `components` array (type: `FEE`) +- **Remaining trading limits**: Provided in `orderAttributes.remainingTradingLimit` including: + - `remainingQuantity`: Remaining tradable quantity in kWh + - `sanctionedLoad`: Breakdown of total, used, and remaining sanctioned load + - `validUntil`: Validity timestamp for the limit information +
-Cascaded Request Example +Cascaded Request Example ```json { - "context": { - "domain": "energy", - "action": "init", - "location": { - "country": { - "name": "India", - "code": "IND" - }, - "city": { - "name": "Lucknow", - "code": "std:522" - } - }, - "version": "1.1.0", - "bap_id": "p2pTrading-bpp.com", - "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v1", - "bpp_id": "example-transmission-bpp.com", - "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", - "transaction_id": "6743e9e2-4fb5-487c-92b7-13ba8018f176", - "message_id": "6743e9e2-4fb5-487c-92b7-13ba8018f176", - "timestamp": "2023-07-16T04:41:16Z" - }, - "message": { - "order": { - "provider": { - "descriptor": { - "name": "UPPCL" - } - }, - "fulfillments": [ - { - "customer": { - "person": { - "name": "Raj" - }, - "contact": { - "phone": "+91-1276522222" - } - }, - "stops": [ - { - "type": "start", - "location": { - "address": "der://uppcl.meter/92982739" - }, - "time": { - "range": { - "start": "2024-10-04T10:00:00", - "end": "2024-10-04T18:00:00" - } - } - }, - { - "type": "end", - "location": { - "address": "der://uppcl.meter/98765456" - }, - "time": { - "range": { - "start": "2024-10-04T10:00:00", - "end": "2024-10-04T18:00:00" - } - } - } - ], - "tags": [ - { - "descriptor": { - "name": "P2P-Trade-Draft-Contract" - }, - "list": [ - { - "Value": "https://https://dhiway.com/vc/energy/3894434.json" - } - ] - } - ] - } + "context": { + "version": "2.0.0", + "action": "init", + "timestamp": "2024-10-04T10:20:00Z", + "message_id": "msg-cascaded-init-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": 15.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" ], - "billing": { - "name": "p2p-Trading-BPP", - "email": "p2tbpp@example.com", - "phone": "+91-1276522222" + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } } + } } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } } + } +} + +``` +
+ +
Immediate successful Response + +```json +{ + "ack_status": "ACK", + "timestamp": "2025-10-14T07:31:05Z" } ```
-Cascaded Response Example +Cascaded asynchronous Response Example: `on_init` ```json { - "context": { - "domain": "energy", - "action": "on_init", - "location": { - "country": { - "name": "India", - "code": "IND" - }, - "city": { - "name": "Lucknow", - "code": "std:522" - } - }, - "version": "1.1.0", + "context": { + "version": "2.0.0", + "action": "on_init", + "timestamp": "2024-10-04T10:20:05Z", + "message_id": "msg-cascaded-on-init-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", "bap_id": "p2pTrading-bpp.com", - "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v1", "bpp_id": "example-transmission-bpp.com", - "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", - "transaction_id": "6743e9e2-4fb5-487c-92b7-13ba8018f176", - "message_id": "6743e9e2-4fb5-487c-92b7-13ba8018f176", - "timestamp": "2023-07-16T04:41:16Z" - }, - "message": { - "order": { - "provider": { - "descriptor": { - "name": "UPPCL" - } + "total_quantity": 15.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" }, - "fulfillments": [ - { - "customer": { - "person": { - "name": "Raj" - }, - "contact": { - "phone": "+91-1276522222" - } - }, - "stops": [ - { - "type": "start", - "location": { - "address": "der://uppcl.meter/92982739" - }, - "time": { - "range": { - "start": "2024-10-04T10:00:00", - "end": "2024-10-04T18:00:00" - } - } - }, - { - "type": "end", - "location": { - "address": "der://uppcl.meter/98765456" - }, - "time": { - "range": { - "start": "2024-10-04T10:00:00", - "end": "2024-10-04T18:00:00" - } - } - } - ], - "tags": [ - { - "descriptor": { - "name": "P2P-Trade-Draft-Contract" - }, - "list": [ - { - "Value": "https://https://dhiway.com/vc/energy/3894434.json" - } - ] - } - ] - } + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" ], - "quote": { - "price": { - "value": "2.5", - "currency": "INR" - }, - "breakup": [ - { - "title": "wheeling charge", - "price": { - "value": "2.5", - "currency": "INR" - } - } - ] - }, - "billing": { - "name": "p2p-Trading-BPP", - "email": "p2ptbpp@example.com", - "phone": "+91-1276522222" - }, - "cancellation_terms": [ - { - "external_ref": { - "mimetype": "text/html", - "url": "https://mvvnl.in/cancellation_terms.html" - } - } - ] + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } } + } } + ```
-## 9.5. Confirm Flow +## 10.5. Confirm Flow **Purpose**: Confirm and activate the order **Endpoint**: `POST /confirm`
-Request Example +Request Example ```json { @@ -1499,56 +1819,171 @@ This flow demonstrates the cascaded `/init` call from the P2P Trading BPP to the "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:fulfillments": [ + }, { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY" + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } } ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ] + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } } } } +``` +
+ +
Immediate successful Response +```json +{ + "ack_status": "ACK", + "timestamp": "2025-10-14T07:31:05Z" +} ```
-Response Example +Asynchronous Response Example: `on_confirm` ```json { @@ -1563,86 +1998,157 @@ This flow demonstrates the cascaded `/init` call from the P2P Trading BPP to the "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 }, - "beckn:fulfillments": [ + "beckn:orderItems": [ { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:state": { - "@type": "beckn:State", + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", "beckn:descriptor": { "@type": "beckn:Descriptor", - "schema:name": "PENDING" + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } } } - } - ], - "beckn:payments": [ + }, { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } } ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "ACTIVE", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "inverterId": "inv-12345", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR", - "certification": { - "status": "Carbon Offset Certified", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - }, - "settlementCycles": [ - { - "cycleId": "settle-2024-10-04-001", - "startTime": "2024-10-04T00:00:00Z", - "endTime": "2024-10-04T23:59:59Z", - "status": "PENDING", - "amount": 0.0, - "currency": "USD" - } - ] + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" } } } } - ```
@@ -1651,445 +2157,859 @@ This flow demonstrates the cascaded `/init` call from the P2P Trading BPP to the - Settlement cycle is initialized - Order is now active and ready for fulfillment -## 9.6. Status Flow +### 10.5.1. Cascaded Confirm Example (Utility Trade Logging) -**Purpose**: Query order and delivery status +This flow demonstrates the cascaded `/confirm` call from the P2P Trading BPP to the Utility Company (Transmission BPP) to log the trade and deduct from trading limits. -**Endpoint**: `POST /status` +**Request Flow**: P2P Trading BPP sends a cascaded `confirm` request to the Utility BPP with the order details to finalize the trade registration. + +**Response Flow**: Utility BPP responds with `on_confirm` containing: +- **Contract activation**: Contract status set to `ACTIVE` in `orderAttributes.contractStatus` +- **Settlement cycle**: Initialized settlement cycle in `orderAttributes.settlementCycles` +- **Updated remaining trading limits**: Provided in `orderAttributes.remainingTradingLimit` with: + - `remainingQuantity`: Updated remaining tradable quantity (reduced by the contracted quantity) + - `sanctionedLoad`: Updated breakdown showing increased `used` and reduced `remaining` values after trade is logged + - `validUntil`: Validity timestamp for the limit information
-Request Example +Cascaded Request Example ```json { "context": { "version": "2.0.0", - "action": "status", - "timestamp": "2024-10-04T15:00:00Z", - "message_id": "msg-status-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", + "action": "confirm", + "timestamp": "2024-10-04T10:25:00Z", + "message_id": "msg-cascaded-confirm-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", - "beckn:id": "order-energy-001" - } - } -} - - -``` -
- -
-Response Example - -```json -{ - "context": { - "version": "2.0.0", - "action": "on_status", - "timestamp": "2024-10-04T15:00:05Z", - "message_id": "msg-on-status-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": 15.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} + +``` +
+ +
+Cascaded asynchronous Response Example: `on_confirm` + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "timestamp": "2024-10-04T10:25:05Z", + "message_id": "msg-cascaded-on-confirm-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" + "beckn:id": "order-cascaded-utility-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": 15.0 }, - "beckn:fulfillments": [ + "beckn:orderItems": [ { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:state": { - "@type": "beckn:State", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "IN_PROGRESS" + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" } }, - "beckn:attributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeDelivery/v0.2/context.jsonld", - "@type": "EnergyTradeDelivery", - "deliveryStatus": "IN_PROGRESS", - "deliveryMode": "GRID_INJECTION", - "deliveredQuantity": 9.8, - "deliveryStartTime": "2024-10-04T10:00:00Z", - "deliveryEndTime": null, - "meterReadings": [ - { - "timestamp": "2024-10-04T10:00:00Z", - "sourceReading": 1000.0, - "targetReading": 990.0, - "energyFlow": 10.0 - }, - { - "timestamp": "2024-10-04T12:00:00Z", - "sourceReading": 1000.5, - "targetReading": 990.3, - "energyFlow": 10.2 - }, - { - "timestamp": "2024-10-04T14:00:00Z", - "sourceReading": 1001.0, - "targetReading": 990.8, - "energyFlow": 10.2 - } + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" ], - "telemetry": [ - { - "eventTime": "2024-10-04T12:00:00Z", - "metrics": [ - { - "name": "ENERGY", - "value": 5.8, - "unitCode": "KWH" - }, - { - "name": "POWER", - "value": 2.5, - "unitCode": "KW" - }, - { - "name": "VOLTAGE", - "value": 240.0, - "unitCode": "VLT" - } - ] + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" } - ], - "settlementCycleId": "settle-2024-10-04-001", - "lastUpdated": "2024-10-04T15:30:00Z" + } } } ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "ACTIVE", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "inverterId": "inv-12345", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR", - "certification": { - "status": "Carbon Offset Certified", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - }, - "settlementCycles": [ - { - "cycleId": "settle-2024-10-04-001", - "startTime": "2024-10-04T00:00:00Z", - "endTime": "2024-10-04T23:59:59Z", - "status": "PENDING", - "amount": 0.0, - "currency": "USD" - } - ], - "lastUpdated": "2024-10-04T15:30:00Z" + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" } } } } - ```
-**Key Points**: -- Response includes EnergyTradeContract attributes (contract status) -- Response includes EnergyTradeDelivery attributes (delivery status, meter readings, telemetry) -- Meter readings show energy flow from source to target -- Telemetry provides real-time energy metrics - ---- - - - -# 10. Field Mapping Reference - -## 10.1. v1 to v2 Field Mapping - -| v1 Location | v2 Location | Notes | -| --------------------------- | -------------------------------- | --------------------- | -| `Item.attributes.*` | `Item.itemAttributes.*` | Attribute path change | -| `Offer.attributes.*` | `Offer.offerAttributes.*` | Attribute path change | -| `Order.attributes.*` | `Order.orderAttributes.*` | Attribute path change | -| `Fulfillment.attributes.*` | `Fulfillment.attributes.*` | No change | -| `der://meter/{id}` | `{id}` (IEEE mRID) | Format change | -| `Tag.value` (energy source) | `itemAttributes.sourceType` | Direct attribute | -| `Tag.value` (settlement) | `offerAttributes.settlementType` | Direct attribute | - -## 10.2. Meter ID Format Migration - -**v1 Format**: `der://pge.meter/100200300` -**v2 Format**: `100200300` (IEEE 2030.5 mRID) - -**Migration Rule**: Extract the numeric ID from the `der://` URI. +## 10.6. Status Flow ---- +**Purpose**: Query order and delivery status -# 11. Integration Patterns +**Endpoint**: `POST /status` -## 11.1. Attaching Attributes to Core Objects +
+Request Example -**Item with EnergyResource**: ```json { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Item", - "beckn:id": "energy-resource-solar-001", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "Solar Energy - 30.5 kWh" + "context": { + "version": "2.0.0", + "action": "status", + "timestamp": "2024-10-04T15:00:00Z", + "message_id": "msg-status-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, - "beckn:itemAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyResource/v0.2/context.jsonld", - "@type": "EnergyResource", - "sourceType": "SOLAR", - "deliveryMode": "GRID_INJECTION", - "meterId": "100200300" + "message": { + "order": { + "beckn:id": "order-energy-001" + } } } ``` +
-**Offer with EnergyTradeOffer**: -```json -{ - "@type": "beckn:Offer", - "beckn:id": "offer-energy-001", - "beckn:offerAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeOffer/v0.2/context.jsonld", - "@type": "EnergyTradeOffer", - "pricingModel": "PER_KWH", - "settlementType": "DAILY" - } -} -``` +
Immediate successful Response -**Order with EnergyTradeContract**: ```json { - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "ACTIVE", - "sourceMeterId": "100200300", - "targetMeterId": "98765456" - } + "ack_status": "ACK", + "timestamp": "2025-10-14T07:31:05Z" } ``` +
+ +
+Asynchronous Response Example: `on_status` -**Fulfillment with EnergyTradeDelivery**: ```json { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:attributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeDelivery/v0.2/context.jsonld", - "@type": "EnergyTradeDelivery", - "deliveryStatus": "IN_PROGRESS", - "meterReadings": [...] + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T15:00:05Z", + "message_id": "msg-on-status-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 7.5, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T15:00:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "PENDING", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 0.0, + "meterReadings": [], + "lastUpdated": "2024-10-04T15:00:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } } } + ``` +
-## 11.2. JSON-LD Context Usage +**Key Points**: +- Response includes EnergyTradeContract attributes (contract status) +- Response includes EnergyTradeDelivery attributes (delivery status, meter readings, telemetry) +- Meter readings show energy flow from source to target +- Telemetry provides real-time energy metrics -All attribute bundles include `@context` and `@type`: -- `@context`: Points to the context.jsonld file for the attribute bundle -- `@type`: The schema type (EnergyResource, EnergyTradeOffer, etc.) +### 10.6.1. Curtailed Trade Status -## 11.3. Discovery Filtering +When a trade has been curtailed (e.g., due to grid outage), the status response includes curtailment information for payment reconciliation: -Use JSONPath filters to search by energy attributes: +
+Curtailed Status Response Example ```json { - "filters": { - "type": "jsonpath", - "expression": "$[?(@.itemAttributes.sourceType == 'SOLAR' && @.itemAttributes.deliveryMode == 'GRID_INJECTION' && @.itemAttributes.availableQuantity >= 10.0)]" + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T16:00:00Z", + "message_id": "msg-on-status-curtailed-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "PARTIALLYFULFILLED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "curtailedQuantity": 5.0, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T14:30:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 10.0, + "allocatedEnergy": 10.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "FAILED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 0.0, + "curtailedQuantity": 10.0, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } } } -``` - ---- - -# 12. Best Practices - -## 12.1. Discovery Optimization - -- **Index Key Fields**: Index `itemAttributes.sourceType`, `itemAttributes.deliveryMode`, `itemAttributes.meterId`, `itemAttributes.availableQuantity` -- **Use JSONPath Filters**: Leverage JSONPath for complex filtering -- **Minimal Fields**: Return minimal fields in list/search APIs (see profile.json) - -## 12.2. Meter ID Handling - -- **Use IEEE mRID Format**: Always use plain identifier (e.g., `"100200300"`), not `der://` format -- **PII Treatment**: Treat meter IDs as PII - do not index, redact in logs, encrypt at rest -- **Discovery**: Meter IDs enable meter-based discovery (provider names not required) - -## 12.3. Settlement Cycle Management - -- **Initialize on Confirm**: Create settlement cycle when order is confirmed -- **Update on Delivery**: Link deliveries to settlement cycles via `settlementCycleId` -- **Status Tracking**: Track settlement cycle status (PENDING → SETTLED → FAILED) -- **Amount Calculation**: Calculate settlement amount based on delivered quantity and pricing -## 12.4. Meter Readings - -- **Regular Updates**: Update meter readings during delivery (every 15-30 minutes) -- **Energy Flow Calculation**: Calculate `energyFlow` as difference between readings -- **Source and Target**: Track both source and target meter readings -- **Timestamp Accuracy**: Use accurate timestamps (ISO 8601 format) +``` +
-## 12.5. Telemetry Data +**Curtailment Fields for Payment Reconciliation**: +- `curtailedQuantity`: Revised trade limit (kWh) - the billable quantity +- `curtailmentReason`: Why curtailment occurred (`GRID_OUTAGE`, `EMERGENCY`, `CONGESTION`, `MAINTENANCE`, `OTHER`) +- `curtailmentTime`: When the curtailment was issued -- **Metric Selection**: Include relevant metrics (ENERGY, POWER, VOLTAGE, CURRENT, FREQUENCY) -- **Unit Codes**: Use correct unit codes (KWH, KW, VLT, AMP, HZ) -- **Update Frequency**: Update telemetry every 5-15 minutes during active delivery -- **Data Retention**: Retain telemetry data for billing and audit purposes +**Payment Calculation**: +- Original contracted: `orderItems[].quantity` +- Actually delivered: `deliveredQuantity` +- Billable amount: `min(deliveredQuantity, curtailedQuantity) × price` -## 12.6. Error Handling +## 10.7. Update Flow (Provider-Initiated) -- **Validation Errors**: Validate all required fields before processing -- **Meter ID Format**: Validate meter IDs are IEEE mRID format -- **Quantity Validation**: Ensure quantities are within min/max limits -- **Time Window Validation**: Validate production windows and validity windows +**Purpose**: Notify BAP of changes to an active order initiated by the provider (BPP) or utility ---- +**Endpoint**: `POST /on_update` (unsolicited callback from BPP to BAP) -# 13. Migration from v1 +In Beckn protocol, `on_update` can be sent **without a preceding `update` request** from BAP. This is the standard "push notification" pattern for provider-initiated changes such as: +- Trade curtailment due to grid outages +- Delivery interruptions +- Settlement adjustments -## 13.1. Key Changes +### 10.7.1. Utility-Initiated Trade Curtailment -1. **Attribute Paths**: Change `attributes.*` to `itemAttributes.*`, `offerAttributes.*`, `orderAttributes.*` -2. **Meter Format**: Convert `der://meter/{id}` to `{id}` (IEEE mRID) -3. **Tag Values**: Convert `Tag.value` to direct attribute fields -4. **JSON-LD**: Add `@context` and `@type` to all attribute objects +During active energy delivery, grid operators may need to curtail trades due to: +- **Grid outages**: Unexpected failures requiring immediate load reduction +- **Emergency conditions**: Frequency deviations, voltage issues +- **Congestion**: Transmission capacity limits +- **Scheduled maintenance**: Planned outages -## 13.2. Migration Checklist +When this happens, the Utility Company sends an unsolicited `on_update` to the BPP, which forwards it to the BAP. This enables both parties to reconcile payments based on the revised trade quantity. -- Update attribute paths (`attributes.*` → `itemAttributes.*`, etc.) -- Convert meter IDs from `der://` format to IEEE mRID -- Replace `Tag.value` with direct attribute fields -- Add JSON-LD context to all attribute objects -- Update discovery filters to use new attribute paths -- Update validation logic for new schema structure -- Test all transaction flows -- Update documentation +```mermaid +sequenceDiagram + participant Utility as Utility Grid Operator + participant BPP as P2P Trading BPP + participant BAP as P2P Trading BAP + + Note over Utility: Grid outage detected + Utility->>BPP: on_update (curtailment notification) + Note right of BPP: curtailedQuantity: 10kWh
curtailmentReason: GRID_OUTAGE + BPP->>BAP: on_update (forwarded) + Note over BAP: Update UI, adjust payment +``` -## 13.3. Example Migration +
+Curtailment Notification Example (`on_update`) -**v1 Format**: ```json { - "Item": { - "attributes": { - "sourceType": "SOLAR", - "meterId": "der://pge.meter/100200300" - } + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T14:30:00Z", + "message_id": "msg-on-update-curtailment-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" }, - "Tag": { - "value": "SOLAR" + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "INPROGRESS", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 8.5, + "curtailedQuantity": 6.5, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 8.5, + "allocatedEnergy": 8.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + } + ] + } } } -``` -**v2 Format**: -```json -{ - "@type": "beckn:Item", - "beckn:itemAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyResource/v0.2/context.jsonld", - "@type": "EnergyResource", - "sourceType": "SOLAR", - "meterId": "100200300" - } -} ``` +
---- - -# 14. Examples - -## 14.1. Complete Examples - -All examples are available in: -- **Schema Examples**: `schema/EnergyResource/v0.2/examples/schema/` - - `item-example.json` - EnergyResource - - `offer-example.json` - EnergyTradeOffer - - `order-example.json` - EnergyTradeContract - - `fulfillment-example.json` - EnergyTradeDelivery - -- **Transaction Flow Examples**: [`/examples/v2/P2P_Trading/`](/examples/v2/P2P_Trading/) - - [`discover-request.json`](/examples/v2/P2P_Trading/discover-request.json) / [`discover-response.json`](/examples/v2/P2P_Trading/discover-response.json) - - [`select-request.json`](/examples/v2/P2P_Trading/select-request.json) / [`select-response.json`](/examples/v2/P2P_Trading/select-response.json) - - [`init-request.json`](/examples/v2/P2P_Trading/init-request.json) / [`init-response.json`](/examples/v2/P2P_Trading/init-response.json) - - [`confirm-request.json`](/examples/v2/P2P_Trading/confirm-request.json) / [`confirm-response.json`](/examples/v2/P2P_Trading/confirm-response.json) - - [`status-request.json`](/examples/v2/P2P_Trading/status-request.json) / [`status-response.json`](/examples/v2/P2P_Trading/status-response.json) +**Key Points**: +- `on_update` is **unsolicited** - no preceding `update` request needed +- Contains `curtailedQuantity` for payment reconciliation +- `curtailmentReason` provides audit trail for dispute resolution +- BAP should update UI and adjust pending payment based on revised quantity -## 14.2. Example Scenarios +# 11. Additional Resources -1. **Solar Energy Discovery**: Search for solar energy with grid injection delivery -2. **Daily Settlement**: Contract with daily settlement cycle -3. **Meter-Based Tracking**: Track energy flow using meter readings -4. **Telemetry Monitoring**: Monitor energy delivery with real-time telemetry +1. **Beckn 1.0 to 2.0 field mapping**: See `./v1_to_v2_field_mapping.md` +2. **Taxonomy Reference**: See `./taxonomy.md` +3. **Solar Energy Discovery**: Search for solar energy with grid injection delivery +4. **Daily Settlement**: Contract with daily settlement cycle +5. **Meter-Based Tracking**: Track energy flow using meter readings +6. **Telemetry Monitoring**: Monitor energy delivery with real-time telemetry --- -## 14.3. Inter energy retailer P2P trading +## 11.1. Inter energy retailer P2P trading This is a specific scenario of P2P trading where the participants come under differnet energy retailers and distribution utilities and engages in direct energy trade. Here, nuances of financial settlement, dispute resolution, energy accounting etc will have to be thought through without affecting ease of participation. More information can be found here [Inter-retailer P2P energy trading](/docs/implementation-guides/v2/P2P_Trading/Inter_energy_retailer_P2P_trading_draft.md) -# 15. Additional Resources +# 12. Additional Resources - **Field Mapping**: See `docs/v1_to_v2_field_mapping.md` - **Taxonomy Reference**: See `docs/TAXONOMY.md` @@ -2097,16 +3017,42 @@ This is a specific scenario of P2P trading where the participants come under dif - **Context Files**: See `schema/Energy*/v0.2/context.jsonld` - **Profile Configuration**: See `schema/EnergyResource/v0.2/profile.json` ---- +### 12.0.1. **Integrating with your software** -# 16. Support +This section gives a general walkthrough of how you would integrate your software with the Beckn network (say the sandbox environment). Refer to the starter kit for details on how to register with the sandbox and get credentials. -For questions or issues: -- Review the examples in `schema/EnergyResource/v0.2/examples/` -- Check the schema definitions in `schema/Energy*/v0.2/attributes.yaml` -- Refer to the Beckn Protocol v2 documentation +Beckn-ONIX is an initiative to promote easy installation and maintenance of a Beckn Network. Apart from the Registry and Gateway components that are required for a network facilitator, Beckn-ONIX provides a Beckn Adapter. A reference implementation of the Beckn-ONIX specification is available at [Beckn-ONIX repository](https://github.com/beckn/beckn-onix). The reference implementation of the Beckn Adapter is called the Protocol Server. Based on whether we are writing the seeker platform or the provider platform, we will be installing the BAP Protocol Server or the BPP Protocol Server respectively. ---- +TODO + +#### 12.0.1.1. **Integrating the BAP** + +If you are writing the seeker platform software, the following are the steps you can follow to build and integrate your application. + +1. **Discovery**: Use JSONPath filters to search by energy attributes (sourceType, deliveryMode, availableQuantity, productionWindow) +2. **Order Management**: Track order state through PENDING → ACTIVE → COMPLETED +3. **Status Polling**: Poll status endpoint every 15-30 minutes during active delivery +4. **Error Handling**: Handle cases where delivery fails or quantities don't match +5. **Settlement**: Monitor settlement cycle status for payment processing + +TODO + +#### 12.0.1.2. **Integrating the BPP** + +If you are writing the provider platform software, the following are the steps you can follow to build and integrate your application. + +6. **Catalog Management**: Keep catalog updated with available energy and accurate production windows +7. **Meter Readings**: Update meter readings regularly during delivery (every 15-30 minutes) +8. **Telemetry**: Provide real-time telemetry data for monitoring +9. **Settlement**: Calculate settlement amounts based on delivered quantity and pricing model +10. **State Management**: Properly transition contract and delivery statuses + +TODO + +## 12.1. FAQs +## 12.2. References +* [Postman collection for EV Charging](/testnet/ev-charging-devkit/postman/) +* [Beckn 1.0 (legacy) Layer2 config for peer to peer trading](https://github.com/beckn/missions/blob/main/DEG2.0/layer2/P2P/trade_1.1.0.yaml) diff --git a/docs/implementation-guides/v2/P2P_Trading/note-on-allocation-settlement-logic.md b/docs/implementation-guides/v2/P2P_Trading/note-on-allocation-settlement-logic.md new file mode 100644 index 00000000..2086ca4f --- /dev/null +++ b/docs/implementation-guides/v2/P2P_Trading/note-on-allocation-settlement-logic.md @@ -0,0 +1,1275 @@ +# P2P Energy Settlement & Allocation + +## 1. The Settlement Problem- [P2P Energy Settlement \& Allocation](#p2p-energy-settlement--allocation) +- [P2P Energy Settlement \& Allocation](#p2p-energy-settlement--allocation) + - [1. The Settlement Problem- P2P Energy Settlement \& Allocation](#1-the-settlement-problem--p2p-energy-settlement--allocation) + - [2. Design Principles for Fair Settlement](#2-design-principles-for-fair-settlement) + - [3. The Min-of-Two Settlement Rule](#3-the-min-of-two-settlement-rule) + - [Why Min-of-Two?](#why-min-of-two) + - [Simple Case: Single Trade](#simple-case-single-trade) + - [4. When Allocation Becomes Necessary](#4-when-allocation-becomes-necessary) + - [Condition 1: Multiple Overlapping Trades](#condition-1-multiple-overlapping-trades) + - [Condition 2: Shortfall (Actual ≠ Contracted)](#condition-2-shortfall-actual--contracted) + - [The Allocation Problem](#the-allocation-problem) + - [5. Distributed Allocation Algorithm](#5-distributed-allocation-algorithm) + - [Pro-Rata Allocation (Recommended)](#pro-rata-allocation-recommended) + - [The 3-Round Settlement Flow](#the-3-round-settlement-flow) + - [Settlement Flow Diagram](#settlement-flow-diagram) + - [Optimality of the 3-Round Approach](#optimality-of-the-3-round-approach) + - [6. Billing Calculation](#6-billing-calculation) + - [For Buyer (Consumer)](#for-buyer-consumer) + - [For Seller (Prosumer)](#for-seller-prosumer) + - [7. Ledger API Integration](#7-ledger-api-integration) + - [Allocation Workflow](#allocation-workflow) + - [Step 1: Platform Creates Trade Record](#step-1-platform-creates-trade-record) + - [Step 2: Discoms Record Allocations (Rounds 1, 2 \& 3)](#step-2-discoms-record-allocations-rounds-1-2--3) + - [Step 3: Platforms Read Final Settlement](#step-3-platforms-read-final-settlement) + - [Step 4: Billing Calculation from Settlement](#step-4-billing-calculation-from-settlement) + - [Error Handling Patterns](#error-handling-patterns) + - [Sequence Diagram](#sequence-diagram) + - [8. Summary](#8-summary) + - [9. Consensus Rules for AI Summit](#9-consensus-rules-for-ai-summit) +- [Appendix A: Deviation-Based Settlement (Alternative)](#appendix-a-deviation-based-settlement-alternative) + - [Overview](#overview) + - [Settlement Formulas](#settlement-formulas) + - [Example](#example) + - [Key Properties](#key-properties) + - [When to Use Which](#when-to-use-which) +- [Appendix B: Detailed Optimality Analysis](#appendix-b-detailed-optimality-analysis) + - [The Centralized Optimum](#the-centralized-optimum) + - [Suboptimality Example: Cross-Linked Trades](#suboptimality-example-cross-linked-trades) + - [FIFO Can Be Worse](#fifo-can-be-worse) + - [Theoretical Bounds](#theoretical-bounds) +- [Appendix C: Side-by-Side Method Comparison](#appendix-c-side-by-side-method-comparison) + - [Scenario](#scenario) + - [Min-of-Two Result](#min-of-two-result) + - [Deviation Result](#deviation-result) + - [Key Insight](#key-insight) + - [Principles Alignment](#principles-alignment) + + +In P2P energy trading, settlement answers the question: **"How much energy was actually exchanged, and who pays whom?"** + +Unlike traditional retail electricity (where the utility supplies whatever you consume), P2P trades involve forward contracts: a buyer and seller agree to exchange a specific quantity at a specific price for a future time slot. The problem arises because: + +1. **Actuals differ from contracts** - A seller with rooftop solar may produce less on a cloudy day; a buyer may consume less than expected +2. **Multiple parties involved** - Each trade involves four entities: Buyer (B), Buyer's Utility (BU), Seller (S), Seller's Utility (SU) +3. **Grid must balance** - Any mismatch is absorbed by the utilities from the open market + +**Example:** Seller contracts to deliver 100 kWh but produces only 70 kWh. Buyer expected 100 kWh but received only 70 kWh. Who bears the cost of the 30 kWh shortfall? The buyer's utility had to procure it from the real-time market at potentially higher prices. + +A good settlement mechanism must answer these questions fairly, consistently, and without creating perverse incentives. + +--- + +## 2. Design Principles for Fair Settlement + +The most important property of any settlement is that it is **dispute-free and agreed by all parties, and verifiable in an audit**. Beyond this foundation, we believe the following principles should guide settlement design in order of decreasing importance: + +- **Principle 1: Shortfall responsibility** + > All else equal, the actor(s) responsible for the shortfall should bear the cost of that shortfall. + + If the seller underproduces, the seller bears the consequence. If the buyer underconsumes, the buyer bears the consequence. If both have shortfalls, they share responsibility proportionally. + + This creates natural alignment and avoids gaming. For P2P trading to grow sustainably, it must reduce costs on the rest of the ecosystem and add positive economic value. **Overpenalizing shortfalls (within reason) is acceptable; underpenalizing is not**, as it creates perverse incentives. + + **Consequence of seller underproduction:** The buyer's utility must procure the energy shortfall from the open market at real-time price ($\text{rtm}_p$). + + **Consequence of buyer underconsumption:** The seller's utility must sell the excess energy in the open market, potentially at a loss compared to the trade price. + +- **Principle 2: Independence & scalability** + > Enable uncoordinated, independent actions between (B, BU) and (S, SU) tuples. + + The buyer's utility should not need to know the seller's meter readings or trades when penalizing buyer underconsumption, and vice versa. This breaks deadlocks and enables scale. + +- **Principle 3: Allocation flexibility** + > Different utilities should be able to use independent allocation logic without violating Principle 1. + + The total penalty for a customer's shortfall should be deterministic, even if individual trade allocations vary. + +- **Principle 4: Reuse existing billing flows** + > Avoid introducing new billing relationships. + + Settlement should work within existing flows: + - Buyer ↔ Buyer's Utility + - Seller ↔ Seller's Utility + - Buyer ↔ Seller (via platform) + + Avoid inter-utility payments if possible. + +- **Principle 5: No surprises for compliant parties** + > If an actor abides by its contract, it should face no penalties or revenue surprises. + + - If a seller produces ≥ contracted quantity, their revenue should be the same regardless of whether the buyer underconsumed + - If a buyer consumes ≥ contracted quantity, their bill should be the same regardless of whether the seller underproduced + +- **Principle 6: Allocation-independent total penalty** + > A customer's total penalty should depend only on their total shortfall, not on how it's allocated across trades. + + This makes allocation logic less critical—it may affect per-trade penalties, but not the total. + +--- + +## 3. The Min-of-Two Settlement Rule + +When allocations to a trade by respective parties differ, a consensus has emerged around the following rule to break the tie. Let's denote it as the **min-of-two** rule: + +$$\text{settle}_k = \min(a^B_k, a^S_k)$$ + +Where: +- $a^B_k$ = Buyer utility's allocation for trade $k$ (capped by buyer's actual consumption) +- $a^S_k$ = Seller utility's allocation for trade $k$ (capped by seller's actual production) +- $\text{settle}_k$ = Final settled quantity for trade $k$ + +There are also alternate settlement rules which can help ease the friction in trade assurance. One such rule "pay for own deviation" is described in Appendix A. + +### Why Min-of-Two? + +1. **Dispute-free** - Both parties independently compute allocations; the minimum is unambiguous +2. **Conservative** - In case of disagreement, the lower value prevails, preventing over-billing + +### Simple Case: Single Trade + +When a buyer has exactly one trade with a seller, settlement is straightforward: + +``` +Trade: T1 between Buyer B1 and Seller S1 + - Contracted: 10 kWh @ 6 INR/kWh + +Actuals: + - B1 consumed: 15 kWh + - S1 produced: 8 kWh + +Settlement: + - Buyer allocation: a^B = min(10, 15) = 10 kWh + - Seller allocation: a^S = min(10, 8) = 8 kWh + - Settled: settle = min(10, 8) = 8 kWh + +Billing: + - Buyer pays seller: 8 kWh × 6 INR = 48 INR + - Buyer pays utility for grid import: (15 - 8) = 7 kWh × 10 INR = 70 INR +``` + +**Analysis:** Seller underproduced by 2 kWh. Buyer's settlement reduced from 10 to 8 kWh, forcing them to import 7 kWh from grid instead of 5 kWh. + +--- + +## 4. When Allocation Becomes Necessary + +The single-trade case is simple. However, **allocation** becomes a distinct problem when: + +### Condition 1: Multiple Overlapping Trades + +A customer may have multiple P2P trades in the same time slot: + +``` +Buyer B1 has two trades in slot 10:00-10:15: + - T1: Buy 10 kWh from Seller S1 @ 5 INR + - T2: Buy 10 kWh from Seller S2 @ 6 INR + +B1's actual consumption: 15 kWh (shortfall of 5 kWh) + +Question: How much of the 15 kWh came from T1 vs T2? +``` + +### Condition 2: Shortfall (Actual ≠ Contracted) + +If a customer's actual meter reading differs from their total contracted quantity, we must decide how to distribute the actual across trades: + +``` +Seller S1 has two trades: + - T1: Sell 10 kWh to Buyer B1 + - T3: Sell 10 kWh to Buyer B2 + +S1's actual production: 15 kWh (shortfall of 5 kWh) + +Question: Which buyer gets shorted? Or is it split proportionally? +``` + +### The Allocation Problem + +When both conditions exist, we have the **allocation problem**: given multiple trades and a meter reading that differs from total contracted quantity, how should the utility allocate the actual reading across trades? + +This is a **per-utility** problem. Each utility (buyer's DISCOM, seller's DISCOM) independently allocates their customer's meter reading across that customer's trades. The final settlement for each trade is then the minimum of both allocations. + +--- + +## 5. Distributed Allocation Algorithm + +### Pro-Rata Allocation (Recommended) + +Each utility allocates proportionally to contracted quantities: + +$$a_k = \text{tr}_k \cdot \min\left(1, \frac{\text{meter}}{\sum_{k'} \text{tr}_{k'}}\right)$$ + +**Example:** +``` +Seller S1: Production = 15 kWh, Contracts = T1(10) + T3(10) = 20 kWh +Pro-rata factor: min(1, 15/20) = 0.75 +Allocations: T1 = 10 × 0.75 = 7.5 kWh, T3 = 10 × 0.75 = 7.5 kWh +``` + +**Properties:** +- Deterministic (no timestamp dependency) +- Fair across trades (proportional sharing) +- Simple to implement +- Each utility computes independently + +### The 3-Round Settlement Flow + +1. **Round 1 - Seller utilities allocate (initial):** Each seller utility computes pro-rata allocations based on seller's production. Records allocated pushed energy to ledger. Marks `statusSellerDiscom` as **PENDING**. + +2. **Round 2 - Buyer utilities allocate:** Each buyer utility queries seller allocations from Round 1, computes pro-rata allocations based on buyer's consumption, and caps each allocation at the seller's Round 1 allocation. Records allocated pulled energy to ledger. Marks `statusBuyerDiscom` as **COMPLETED**. + +3. **Round 3 - Seller utilities re-allocate (final):** Each seller utility queries buyer allocations from Round 2, re-computes allocations capped at buyer's Round 2 values. This allows sellers to redistribute freed-up energy from trades where buyers took less than offered. Records updated allocations to ledger. Marks `statusSellerDiscom` as **COMPLETED**. + +After Round 3, both allocations converge: the seller's final allocation equals the buyer's allocation for each trade. The min-of-two rule $\text{settle}_k = \min(a^B_k, a^S_k)$ becomes a verification rather than a computation, since both values should agree. + +**Why seller first?** Production (supply) is typically the scarcer constraint. The seller's initial allocation sets the upper bound, the buyer responds within that bound, and the seller finalizes. This 3-round convergence ensures both parties explicitly agree on settled quantities. + +**Why 3 rounds instead of 2?** When a seller has multiple trades and some buyers consume less than offered, Round 3 allows the seller's utility to redistribute the surplus to other trades where the buyer could accept more. Without Round 3, this surplus would be stranded. + +### Settlement Flow Diagram + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ Post-Delivery Settlement │ +├─────────────────────────────────────────────────────────────────────┤ +│ │ +│ 1. METER READING 2. ALLOCATION 3. BILLING │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ m_i = 100 │ → │ alloc = 80 │ → │ utility_bill│ │ +│ │ (consumed) │ │ (from P2P) │ │ = 20 × tariff│ +│ └─────────────┘ └─────────────┘ └─────────────┘ │ +│ │ +│ Total Consumption = P2P Settled + Utility Import │ +│ 100 kWh = 80 kWh + 20 kWh │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +### Optimality of the 3-Round Approach + +**When is it optimal?** +- **No shortfalls:** If all parties meet their contracts, settlement equals contract for every trade. Trivially optimal. +- **Single-side shortfall:** If only sellers (or only buyers) have shortfalls, the algorithm is optimal. + +**When is it suboptimal?** +- **Both-side shortfalls with cross-linked trades:** When buyers and sellers both have shortfalls, and trades form a bipartite graph with multiple edges, the distributed algorithm can leave energy "stranded." + +**Practical performance:** The 3-round pro-rata approach achieves **67-90% of the theoretical optimum** in worst-case scenarios. In typical scenarios (mild, correlated shortfalls), the gap is much smaller (<10%). See Appendix B for detailed analysis. + +**Recommendation:** Use pro-rata allocation. It is simple, fair, and adequate for most practical scenarios. + +--- + +## 6. Billing Calculation + +### For Buyer (Consumer) + +| Component | Formula | Description | +|-----------|---------|-------------| +| Meter Reading | $m_i$ | Actual consumption (kWh) | +| P2P Settled | $\sum_{k: b(k)=i} \text{settle}_k$ | Energy from P2P trades | +| Utility Import | $m_i - \sum \text{settle}_k$ | Remaining from grid | +| P2P Cost | $\sum \text{settle}_k \times p_k$ | Payment to sellers | +| Utility Cost | $(m_i - \sum \text{settle}_k) \times \text{tariff}_{\text{import}}$ | Grid charges | + +### For Seller (Prosumer) + +| Component | Formula | Description | +|-----------|---------|-------------| +| Meter Reading | $m_j$ | Actual production (kWh) | +| P2P Settled | $\sum_{k: s(k)=j} \text{settle}_k$ | Energy sold via P2P | +| Utility Export | $m_j - \sum \text{settle}_k$ | Remaining to grid | +| P2P Revenue | $\sum \text{settle}_k \times p_k$ | Payment from buyers | +| Utility Revenue | $(m_j - \sum \text{settle}_k) \times \text{tariff}_{\text{export}}$ | Net metering credits | + +--- + +## 7. Ledger API Integration + +The DEG Ledger Service provides an immutable, multi-party view of trade lifecycle events. It supports three primary operations: + +| Endpoint | Who Uses | Purpose | +|----------|----------|---------| +| `POST /ledger/put` | Platforms only | Create/update trade records | +| `POST /ledger/record` | Discoms only | Record actuals and status | +| `POST /ledger/get` | All parties | Query records (policy-filtered) | + +### Allocation Workflow + +``` +Timeline (generic — see "Consensus Rules for AI Summit" for specific time gates): + Delivery period ends + Meter readings become available to discoms + Round 1: Seller discom allocates (ACTUAL_PUSHED), statusSellerDiscom = PENDING + Round 2: Buyer discom reads seller allocations, allocates (ACTUAL_PULLED), + statusBuyerDiscom = COMPLETED + Round 3: Seller discom reads buyer allocations, re-allocates (ACTUAL_PUSHED), + statusSellerDiscom = COMPLETED + Trading platforms read final settled status +``` + +### Step 1: Platform Creates Trade Record + +When a trade is confirmed, the platform creates a ledger record via `/ledger/put`. + +```python +def create_trade_record(trade: Trade) -> LedgerWriteResponse: + """ + Platform creates the initial ledger record at trade confirmation. + Called by: Buyer Platform or Seller Platform + Endpoint: POST /ledger/put + """ + payload = { + "role": "BUYER", # or "SELLER" depending on calling platform + "transactionId": trade.transaction_id, + "orderItemId": trade.order_item_id, + + # Party identifiers + "platformIdBuyer": trade.bap_id, + "platformIdSeller": trade.bpp_id, + "discomIdBuyer": trade.buyer_discom_id, + "discomIdSeller": trade.seller_discom_id, + "buyerId": trade.buyer_ca_number, # Consumer Account number + "sellerId": trade.seller_der_id, # DER / prosumer ID + + # Time metadata + "tradeTime": trade.confirmed_at.isoformat() + "Z", + "deliveryStartTime": trade.delivery_slot_start.isoformat() + "Z", + "deliveryEndTime": trade.delivery_slot_end.isoformat() + "Z", + + # Trade details + "tradeDetails": [{ + "tradeType": "ENERGY", + "tradeQty": trade.contracted_kwh, + "tradeUnit": "KWH" + }], + + # Idempotency token for safe retries + "clientReference": f"platform-create-{trade.order_item_id}" + } + + response = requests.post( + f"{LEDGER_HOST}/ledger/put", + json=payload, + headers=get_signed_headers(payload) + ) + + if response.status_code == 200: + result = response.json() + # Store recordId for future reference + trade.ledger_record_id = result["recordId"] + trade.ledger_row_digest = result["rowDigest"] + return result + elif response.status_code == 409: + # Record already exists - idempotent retry is safe + raise ConflictError(response.json()) + else: + raise LedgerAPIError(response.status_code, response.json()) +``` + +### Step 2: Discoms Record Allocations (Rounds 1, 2 & 3) + +After the delivery period, discoms compute and record allocations in three sequential rounds: +- **Round 1:** Seller discoms allocate based on production (pro-rata). Mark `statusSellerDiscom = PENDING`. +- **Round 2:** Buyer discoms query seller allocations from Round 1, then allocate based on consumption, capped at seller's allocation. Mark `statusBuyerDiscom = COMPLETED`. +- **Round 3:** Seller discoms query buyer allocations from Round 2, then re-allocate capped at buyer's allocation. This allows redistribution of surplus from trades where buyers took less. Mark `statusSellerDiscom = COMPLETED`. + +```python +def compute_pro_rata_allocation( + customer_id: str, + meter_reading: float, + trades: list[Trade] +) -> dict[str, float]: + """ + Pro-rata allocation algorithm. + Allocates meter reading proportionally across all trades for a customer. + + Returns: {order_item_id: allocated_qty} + """ + total_contracted = sum(t.contracted_kwh for t in trades) + + if total_contracted == 0: + return {t.order_item_id: 0.0 for t in trades} + + # Pro-rata factor: ratio of actual to contracted (capped at 1.0) + pro_rata_factor = min(1.0, meter_reading / total_contracted) + + allocations = {} + for trade in trades: + # Each trade gets proportional share of actual meter reading + allocated = trade.contracted_kwh * pro_rata_factor + allocations[trade.order_item_id] = round(allocated, 3) + + return allocations + + +def record_discom_actuals( + role: str, # "BUYER_DISCOM" or "SELLER_DISCOM" + trade: Trade, + allocated_qty: float, + status: str = "COMPLETED" +) -> LedgerWriteResponse: + """ + Discom records fulfillment actuals for a trade. + Called by: Buyer Discom or Seller Discom + Endpoint: POST /ledger/record + + Validation metric types: + - ACTUAL_PUSHED: Energy pushed by seller (seller discom records) + - ACTUAL_PULLED: Energy pulled by buyer (buyer discom records) + """ + payload = { + "role": role, + "transactionId": trade.transaction_id, + "orderItemId": trade.order_item_id, + "clientReference": f"{role.lower()}-actuals-{trade.order_item_id}-{uuid4()}" + } + + if role == "SELLER_DISCOM": + payload["sellerFulfillmentValidationMetrics"] = [{ + "validationMetricType": "ACTUAL_PUSHED", + "validationMetricValue": allocated_qty + }] + payload["statusSellerDiscom"] = status + elif role == "BUYER_DISCOM": + payload["buyerFulfillmentValidationMetrics"] = [{ + "validationMetricType": "ACTUAL_PULLED", + "validationMetricValue": allocated_qty + }] + payload["statusBuyerDiscom"] = status + else: + raise ValueError(f"Invalid role: {role}") + + response = requests.post( + f"{LEDGER_HOST}/ledger/record", + json=payload, + headers=get_signed_headers(payload) + ) + + if response.status_code == 200: + return response.json() + elif response.status_code == 404: + # Record doesn't exist - platform must create first + raise RecordNotFoundError( + f"Ledger record not found for {trade.transaction_id}/{trade.order_item_id}" + ) + elif response.status_code == 403: + # Role not authorized to write these fields + raise AuthorizationError(response.json()) + else: + raise LedgerAPIError(response.status_code, response.json()) + + +def seller_discom_allocation_job( + delivery_slot: TimeSlot, + discom_id: str +): + """ + Round 1: Batch job run by seller discom after delivery period. + + Computes pro-rata allocations based on seller production and records to ledger. + This runs FIRST - buyer discoms will query these allocations in Round 2. + Marks statusSellerDiscom as PENDING (final status set in Round 3). + """ + # Get all trades for this discom in the delivery slot + trades = get_trades_by_seller_discom(discom_id, delivery_slot) + + # Group trades by seller + trades_by_seller = group_by(trades, key=lambda t: t.seller_id) + + for seller_id, seller_trades in trades_by_seller.items(): + # Get meter reading for this seller (production) + meter_reading = get_meter_reading(seller_id, delivery_slot, type="GENERATION") + + # Compute pro-rata allocation + allocations = compute_pro_rata_allocation(seller_id, meter_reading, seller_trades) + + # Record each allocation to ledger with PENDING status + for trade in seller_trades: + allocated_qty = allocations[trade.order_item_id] + record_discom_actuals( + role="SELLER_DISCOM", + trade=trade, + allocated_qty=allocated_qty, + status="PENDING" # Round 1: initial allocation, not yet final + ) + log.info(f"Seller Round 1 allocation recorded: {trade.order_item_id} = {allocated_qty} kWh") + + +def get_seller_allocations_from_ledger( + delivery_slot: TimeSlot, + discom_id: str +) -> dict[str, float]: + """ + Query ledger to get seller allocations recorded in Round 1. + Returns: {order_item_id: seller_allocated_qty} + """ + records = query_ledger_records(delivery_slot, discom_id=discom_id) + + seller_allocations = {} + for record in records: + seller_alloc = extract_allocation(record, "SELLER") + if seller_alloc is not None: + seller_allocations[record["orderItemId"]] = seller_alloc + + return seller_allocations + + +def compute_pro_rata_allocation_with_cap( + customer_id: str, + meter_reading: float, + trades: list[Trade], + other_party_allocations: dict[str, float] +) -> dict[str, float]: + """ + Pro-rata allocation capped at other party's allocation. + + Used in Round 2 (buyer caps at seller's Round 1 allocation) and + Round 3 (seller caps at buyer's Round 2 allocation). + + Returns: {order_item_id: allocated_qty} + """ + total_contracted = sum(t.contracted_kwh for t in trades) + + if total_contracted == 0: + return {t.order_item_id: 0.0 for t in trades} + + # Pro-rata factor: ratio of actual to contracted (capped at 1.0) + pro_rata_factor = min(1.0, meter_reading / total_contracted) + + allocations = {} + for trade in trades: + # Base pro-rata share + pro_rata_share = trade.contracted_kwh * pro_rata_factor + + # Cap at seller's allocation from Round 1 (if available) + seller_alloc = other_party_allocations.get(trade.order_item_id) + if seller_alloc is not None: + capped = min(pro_rata_share, seller_alloc) + else: + # Seller hasn't recorded yet - use pro-rata only + capped = pro_rata_share + + allocations[trade.order_item_id] = round(capped, 3) + + return allocations + + +def buyer_discom_allocation_job( + delivery_slot: TimeSlot, + discom_id: str +): + """ + Round 2: Batch job run by buyer discom after seller discoms have allocated (Round 1). + + 1. Queries ledger to get seller allocations from Round 1 + 2. Computes pro-rata allocations based on buyer consumption + 3. Caps each allocation at seller's allocation (can't pull more than pushed) + 4. Records to ledger with statusBuyerDiscom = COMPLETED + """ + # Get all trades for this discom in the delivery slot + trades = get_trades_by_buyer_discom(discom_id, delivery_slot) + + # Query seller allocations from Round 1 + seller_allocations = get_seller_allocations_from_ledger(delivery_slot, discom_id) + log.info(f"Retrieved {len(seller_allocations)} seller allocations from Round 1") + + # Group trades by buyer + trades_by_buyer = group_by(trades, key=lambda t: t.buyer_id) + + for buyer_id, buyer_trades in trades_by_buyer.items(): + # Get meter reading for this buyer (consumption) + meter_reading = get_meter_reading(buyer_id, delivery_slot, type="CONSUMPTION") + + # Compute pro-rata allocation, capped at seller's allocation + allocations = compute_pro_rata_allocation_with_cap( + buyer_id, + meter_reading, + buyer_trades, + seller_allocations + ) + + # Record each allocation to ledger + for trade in buyer_trades: + allocated_qty = allocations[trade.order_item_id] + seller_alloc = seller_allocations.get(trade.order_item_id, "N/A") + record_discom_actuals( + role="BUYER_DISCOM", + trade=trade, + allocated_qty=allocated_qty, + status="COMPLETED" # Round 2: buyer allocation is final + ) + log.info( + f"Buyer Round 2 allocation recorded: {trade.order_item_id} = {allocated_qty} kWh " + f"(capped at seller's {seller_alloc} kWh)" + ) + + +def get_buyer_allocations_from_ledger( + delivery_slot: TimeSlot, + discom_id: str +) -> dict[str, float]: + """ + Query ledger to get buyer allocations recorded in Round 2. + Returns: {order_item_id: buyer_allocated_qty} + """ + records = query_ledger_records(delivery_slot, discom_id=discom_id) + + buyer_allocations = {} + for record in records: + buyer_alloc = extract_allocation(record, "BUYER") + if buyer_alloc is not None: + buyer_allocations[record["orderItemId"]] = buyer_alloc + + return buyer_allocations + + +def seller_discom_reallocation_job( + delivery_slot: TimeSlot, + discom_id: str +): + """ + Round 3: Batch job run by seller discom after buyer discoms have allocated (Round 2). + + 1. Queries ledger to get buyer allocations from Round 2 + 2. Re-computes pro-rata allocations based on seller production + 3. Caps each allocation at buyer's allocation + 4. Records updated allocations to ledger with statusSellerDiscom = COMPLETED + + This allows redistribution: if a buyer took less than the seller initially + offered in Round 1, the seller can reallocate that surplus to other trades + where buyers accepted the full allocation. + """ + # Get all trades for this discom in the delivery slot + trades = get_trades_by_seller_discom(discom_id, delivery_slot) + + # Query buyer allocations from Round 2 + buyer_allocations = get_buyer_allocations_from_ledger(delivery_slot, discom_id) + log.info(f"Retrieved {len(buyer_allocations)} buyer allocations from Round 2") + + # Group trades by seller + trades_by_seller = group_by(trades, key=lambda t: t.seller_id) + + for seller_id, seller_trades in trades_by_seller.items(): + # Get meter reading for this seller (production) + meter_reading = get_meter_reading(seller_id, delivery_slot, type="GENERATION") + + # Re-compute pro-rata allocation, capped at buyer's Round 2 allocation + allocations = compute_pro_rata_allocation_with_cap( + seller_id, + meter_reading, + seller_trades, + buyer_allocations + ) + + # Record updated allocations to ledger with COMPLETED status + for trade in seller_trades: + allocated_qty = allocations[trade.order_item_id] + buyer_alloc = buyer_allocations.get(trade.order_item_id, "N/A") + record_discom_actuals( + role="SELLER_DISCOM", + trade=trade, + allocated_qty=allocated_qty, + status="COMPLETED" # Round 3: seller allocation is now final + ) + log.info( + f"Seller Round 3 re-allocation recorded: {trade.order_item_id} = {allocated_qty} kWh " + f"(capped at buyer's {buyer_alloc} kWh)" + ) +``` + +### Step 3: Platforms Read Final Settlement + +After all three discom allocation rounds are complete (both `statusSellerDiscom` and `statusBuyerDiscom` are `COMPLETED`), trading platforms and settlement engines can query the ledger to read the final converged allocations. The min-of-two rule is applied as a verification — after convergence, both allocations should agree. + +```python +def query_ledger_records( + delivery_slot: TimeSlot, + discom_id: str = None, + buyer_id: str = None, + seller_id: str = None +) -> list[LedgerRecord]: + """ + Query ledger records by filters. + Endpoint: POST /ledger/get + + Access control: Server enforces record-level and field-level visibility + based on caller identity. + """ + payload = { + "deliveryStartFrom": delivery_slot.start.isoformat() + "Z", + "deliveryStartTo": delivery_slot.end.isoformat() + "Z", + "limit": 500, + "offset": 0, + "sort": "deliveryStartTime", + "sortOrder": "asc" + } + + # Add optional filters + if discom_id: + payload["discomIdBuyer"] = discom_id # or discomIdSeller + if buyer_id: + payload["buyerId"] = buyer_id + if seller_id: + payload["sellerId"] = seller_id + + response = requests.post( + f"{LEDGER_HOST}/ledger/get", + json=payload, + headers=get_signed_headers(payload) + ) + + if response.status_code == 200: + result = response.json() + return result["records"] + else: + raise LedgerAPIError(response.status_code, response.json()) + + +def extract_allocation(record: LedgerRecord, role: str) -> float | None: + """ + Extract allocated quantity from ledger record for a given role. + """ + if role == "SELLER": + metrics = record.get("sellerFulfillmentValidationMetrics", []) + for m in metrics: + if m["validationMetricType"] == "ACTUAL_PUSHED": + return m["validationMetricValue"] + elif role == "BUYER": + metrics = record.get("buyerFulfillmentValidationMetrics", []) + for m in metrics: + if m["validationMetricType"] == "ACTUAL_PULLED": + return m["validationMetricValue"] + return None + + +def compute_settlement(record: LedgerRecord) -> SettlementResult: + """ + Apply min-of-two settlement rule to a ledger record. + + settle_k = min(buyer_allocation, seller_allocation) + """ + trade_qty = record["tradeDetails"][0]["tradeQty"] # Contracted quantity + + # Extract allocations from both discoms + seller_alloc = extract_allocation(record, "SELLER") + buyer_alloc = extract_allocation(record, "BUYER") + + # Handle missing allocations + if seller_alloc is None: + raise SettlementError( + f"Missing seller allocation for {record['recordId']}" + ) + if buyer_alloc is None: + raise SettlementError( + f"Missing buyer allocation for {record['recordId']}" + ) + + # Min-of-two rule + settled_qty = min(seller_alloc, buyer_alloc) + + return SettlementResult( + record_id=record["recordId"], + transaction_id=record["transactionId"], + order_item_id=record["orderItemId"], + contracted_qty=trade_qty, + seller_allocation=seller_alloc, + buyer_allocation=buyer_alloc, + settled_qty=settled_qty, + seller_shortfall=trade_qty - seller_alloc, + buyer_shortfall=trade_qty - buyer_alloc + ) + + +def settlement_batch_job(delivery_slot: TimeSlot): + """ + Main settlement job run after all 3 discom allocation rounds are complete. + Queries ledger, verifies convergence via min-of-two, generates billing records. + + After the 3-round convergence, seller_alloc (Round 3) should equal + buyer_alloc (Round 2) for each trade. The min-of-two serves as verification. + """ + # Query all records for the delivery slot + records = query_ledger_records(delivery_slot) + + settlements = [] + errors = [] + + for record in records: + try: + # Verify both discoms have recorded + if (record.get("statusSellerDiscom") not in ["COMPLETED", "CURTAILED_OUTAGE"] or + record.get("statusBuyerDiscom") not in ["COMPLETED", "CURTAILED_OUTAGE"]): + log.warning(f"Skipping {record['recordId']}: awaiting discom status") + continue + + settlement = compute_settlement(record) + settlements.append(settlement) + + log.info( + f"Settlement computed: {settlement.order_item_id} " + f"contracted={settlement.contracted_qty} " + f"seller_alloc={settlement.seller_allocation} " + f"buyer_alloc={settlement.buyer_allocation} " + f"settled={settlement.settled_qty}" + ) + + except SettlementError as e: + errors.append((record["recordId"], str(e))) + log.error(f"Settlement error for {record['recordId']}: {e}") + + # Generate billing records from settlements + generate_billing_records(settlements) + + return SettlementBatchResult( + delivery_slot=delivery_slot, + total_records=len(records), + settled_count=len(settlements), + error_count=len(errors), + errors=errors + ) +``` + +### Step 4: Billing Calculation from Settlement + +```python +@dataclass +class BillingRecord: + buyer_id: str + seller_id: str + settled_qty: float + p2p_cost: float # settled_qty × trade_price + wheeling_cost: float # settled_qty × wheeling_rate + grid_import: float # buyer_consumption - settled_qty + grid_cost: float # grid_import × grid_tariff + + +def generate_billing_records(settlements: list[SettlementResult]): + """ + Convert settlement results into billing line items. + """ + for s in settlements: + trade = get_trade(s.transaction_id, s.order_item_id) + + billing = BillingRecord( + buyer_id=trade.buyer_id, + seller_id=trade.seller_id, + settled_qty=s.settled_qty, + p2p_cost=s.settled_qty * trade.price_per_kwh, + wheeling_cost=s.settled_qty * trade.wheeling_rate, + grid_import=trade.buyer_meter_reading - s.settled_qty, + grid_cost=(trade.buyer_meter_reading - s.settled_qty) * get_grid_tariff() + ) + + # Persist billing record + save_billing_record(billing) + + # Trigger payment flows + initiate_buyer_to_seller_payment(billing) + initiate_buyer_to_utility_payment(billing) +``` + +### Error Handling Patterns + +```python +# Status codes and their meanings +LEDGER_ERROR_CODES = { + "SCH_FIELD_NOT_ALLOWED": "Field not allowed in request schema", + "SCH_MISSING_REQUIRED": "Required field missing", + "AUT_SIGNATURE_INVALID": "Request signature verification failed", + "AUT_NOT_AUTHORIZED": "Caller not authorized for this operation", + "PRC_CONFLICT": "Immutable field conflict on existing record", + "PRC_NOT_FOUND": "Target record not found", + "SRV_INTERNAL_ERROR": "Internal server error" +} + +def handle_ledger_error(response: requests.Response): + """ + Standard error handling for ledger API responses. + """ + error = response.json() + code = error.get("code") + message = error.get("message") + + if response.status_code == 400: + # Schema/validation error - fix request and retry + raise ValidationError(f"{code}: {message}") + + elif response.status_code == 401: + # Signature invalid - check signing key + raise AuthenticationError(f"{code}: {message}") + + elif response.status_code == 403: + # Not authorized - role cannot perform this action + raise AuthorizationError(f"{code}: {message}") + + elif response.status_code == 404: + # Record not found - platform must create first + raise RecordNotFoundError(f"{code}: {message}") + + elif response.status_code == 409: + # Conflict - immutable field mismatch + raise ConflictError(f"{code}: {message}") + + else: + raise LedgerAPIError(response.status_code, f"{code}: {message}") +``` + +### Sequence Diagram + +``` +┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐ +│ Buyer │ │ Seller │ │ Ledger │ │ Seller │ │ Buyer │ │Trading │ +│ Platform│ │ Platform│ │ Service │ │ Discom │ │ Discom │ │Platform│ +└────┬────┘ └────┬────┘ └────┬────┘ └────┬─────┘ └────┬─────┘ └───┬────┘ + │ │ │ │ │ │ + │ Trade Confirmed │ │ │ │ + │─────────────────────────> │ │ │ + │ POST /ledger/put │ │ │ │ + │ (create record) │ │ │ │ + │ │ │ │ │ │ + │ │<───────────│ │ │ │ + │ │ recordId │ │ │ │ + │ │ │ │ │ │ + │ │ │ │ + │ │ │ ══ ROUND 1: Seller Allocates (PENDING) ══ + │ │ │ Meter readings available │ + │ │ │ │ │ │ + │ │ │<───────────│ │ │ + │ │ │ POST /ledger/record │ │ + │ │ │ ACTUAL_PUSHED=70 kWh │ │ + │ │ │ statusSellerDiscom=PENDING │ + │ │ │───────────>│ │ │ + │ │ │ OK │ │ │ + │ │ │ │ │ │ + │ │ │ ══ ROUND 2: Buyer Allocates (COMPLETED) ══ + │ │ │ Buyer queries seller allocs │ + │ │ │ │ │ │ + │ │ │<────────────────────────── │ + │ │ │ POST /ledger/get │ + │ │ │ (get seller allocations) │ + │ │ │──────────────────────────> │ + │ │ │ ACTUAL_PUSHED=70 kWh │ + │ │ │ │ │ │ + │ │ │ │ Buyer computes pro-rata │ + │ │ │ │ consumption=80, cap at 70│ + │ │ │ │ │ │ + │ │ │<────────────────────────── │ + │ │ │ POST /ledger/record │ + │ │ │ ACTUAL_PULLED=70 kWh (capped) │ + │ │ │ statusBuyerDiscom=COMPLETED │ + │ │ │──────────────────────────> │ + │ │ │ OK │ │ │ + │ │ │ │ │ │ + │ │ │ ══ ROUND 3: Seller Re-Allocates (COMPLETED) ══ + │ │ │ Seller queries buyer allocs │ + │ │ │ │ │ │ + │ │ │<───────────│ │ │ + │ │ │ POST /ledger/get │ │ + │ │ │ (get buyer allocations) │ │ + │ │ │───────────>│ │ │ + │ │ │ ACTUAL_PULLED=70 kWh │ │ + │ │ │ │ │ │ + │ │ │ Seller re-computes, caps at buyer's 70│ + │ │ │ │ │ │ + │ │ │<───────────│ │ │ + │ │ │ POST /ledger/record │ │ + │ │ │ ACTUAL_PUSHED=70 kWh (confirmed) │ + │ │ │ statusSellerDiscom=COMPLETED │ + │ │ │───────────>│ │ │ + │ │ │ OK │ │ │ + │ │ │ │ │ │ + │ │ │ ══ SETTLEMENT: Platforms Read Final Status ══ + │ │ │ Both statuses COMPLETED │ + │ │ │ │ │ │ + │ │ │<─────────────────────────────────────│ + │ │ │ POST /ledger/get │ + │ │ │ (query by delivery slot) │ + │ │ │─────────────────────────────────────>│ + │ │ │ seller=70, buyer=70 (converged) │ + │ │ │ │ │ │ + │ │ │ │ │ settled = min(70, 70) = 70 kWh + │ │ │ │ │ → Generate billing +``` + +**Key insight:** The 3-round process ensures convergence. In Round 1, the seller discom sets the upper bound (70 kWh based on production). In Round 2, the buyer discom allocates within that bound (70 kWh, capped from 80 kWh consumption). In Round 3, the seller discom confirms by re-allocating within the buyer's bound. After convergence, both allocations agree, and the min-of-two verification yields `min(70, 70) = 70 kWh`. + +--- + +## 8. Summary + +| Aspect | Min-of-Two Settlement | +|--------|----------------------| +| Settlement rule | $\text{settle}_k = \min(a^B_k, a^S_k)$ | +| Allocation method | Pro-rata (recommended) | +| Flow | Seller allocates (PENDING) → Buyer allocates (COMPLETED) → Seller re-allocates (COMPLETED) | +| Optimality | 67-90% of global optimum in worst case | +| Complexity | Simple, no optimization solvers needed | + +The min-of-two approach satisfies our design principles: +- **Dispute-free:** Minimum is unambiguous +- **Shortfall accountability:** Underproduce/underconsume → reduced settlement +- **Independence:** Each utility allocates based only on its customers' meters +- **Existing flows:** No inter-utility payments required + +--- + +## 9. Consensus Rules for AI Summit + +The following time gates define the settlement schedule agreed upon for the AI Summit demonstration. These are specific deadlines for each round of the 3-round allocation flow. + +**Assumptions:** +- Delivery window: **6:00 AM to 7:00 AM** +- Meter data available with discoms by: **next day, 9:00 AM** + +| Round | Actor | Deadline | Action | Status Field | +|-------|-------|----------|--------|--------------| +| 1 | Seller Discom | 9:55 AM | Writes allocations (ACTUAL_PUSHED) to ledger | `statusSellerDiscom = PENDING` | +| 2 | Buyer Discom | 10:55 AM | Reads ledger (by 10:00 AM), writes allocations (ACTUAL_PULLED) capped at seller's Round 1 values | `statusBuyerDiscom = COMPLETED` | +| 3 | Seller Discom | 11:55 AM | Reads buyer allocations, writes final allocations capped at buyer's Round 2 values | `statusSellerDiscom = COMPLETED` | +| — | Trading Platforms | 12:00 PM (noon) | Read final settled status from ledger | Both statuses `COMPLETED` | + +``` +Timeline (AI Summit): + + Day 1 + ├── 06:00 AM Delivery window starts + └── 07:00 AM Delivery window ends + + Day 2 (next morning) + ├── 09:00 AM Meter data available with discoms + ├── 09:55 AM [Round 1] Seller discom writes allocations → statusSellerDiscom = PENDING + ├── 10:00 AM Buyer discom reads seller allocations from ledger + ├── 10:55 AM [Round 2] Buyer discom writes allocations → statusBuyerDiscom = COMPLETED + ├── 11:55 AM [Round 3] Seller discom writes final allocations → statusSellerDiscom = COMPLETED + └── 12:00 PM Trading platforms read final settlement status +``` + +**Notes:** +- All times refer to the day after the delivery window (D+1). +- Each round has a ~55-minute window to allow for batch processing across all trades in the delivery slot. +- The 5-minute gap between rounds (e.g., 9:55 AM finish → 10:00 AM read) allows the ledger to propagate writes before the next reader begins. +- If a discom misses its deadline, the trade remains in an incomplete state and must be handled through exception processes. + +--- + +# Appendix A: Deviation-Based Settlement (Alternative) + +This appendix describes an alternative settlement method based on **explicit deviation penalties** rather than reduced settlement quantities. + +## Overview + +| Aspect | Min-of-Two | Deviation Method | +|--------|------------|------------------| +| Inter-utility coordination | Required (3 rounds) | **Not required** | +| Penalty mechanism | Implicit (reduced settlement) | Explicit (deviation charges) | +| Revenue for compliant party | Depends on other party | **Guaranteed if you comply** | +| Complexity | Simpler billing | More line items | + +## Settlement Formulas + +**Buyer pays:** +$$\text{Buyer Payment} = \text{tr}_q \times \text{tr}_p - (\text{tr}_q - \text{load}_q) \times \text{exportBU}_p$$ + +- Pays full contract value +- Minus: credit for underconsumption (utility sells surplus at spot) + +**Seller receives:** +$$\text{Seller Revenue} = \text{tr}_q \times \text{tr}_p - (\text{tr}_q - \text{gen}_q) \times \text{importSU}_p$$ + +- Receives full contract value +- Minus: penalty for underproduction (utility procures shortfall) + +**Utility flows:** +- Seller utility receives: $(\text{tr}_q - \text{gen}_q) \times \text{importSU}_p$ +- Buyer utility pays: $(\text{tr}_q - \text{load}_q) \times \text{exportBU}_p$ + +**Zero-sum verification:** All flows balance to zero. + +## Example + +``` +Trade: 10 kWh @ 6 INR/kWh +Actuals: load_q = 8 kWh, gen_q = 7 kWh +Rates: exportBU_p = 4 INR, importSU_p = 8 INR + +Buyer pays: 10×6 - (10-8)×4 = 60 - 8 = 52 INR +Seller gets: 10×6 - (10-7)×8 = 60 - 24 = 36 INR +SU receives: (10-7)×8 = 24 INR +BU pays: (10-8)×4 = 8 INR + +Verify: 52 - 36 - 24 + 8 = 0 ✓ +``` + +## Key Properties + +**1. No coordination needed** +Each utility computes penalties independently based only on its customer's meter. + +**2. Contract compliance guarantees revenue** +If seller produces ≥ contract: receives full $\text{tr}_q \times \text{tr}_p$ regardless of buyer behavior. + +**3. Allocation doesn't affect total penalty** +Total penalty = (total contract - total meter) × rate. Independent of per-trade allocation. + +**4. Utility margin for risk** +Utilities can set $\text{importSU}_p > \text{rtm}_p$ and $\text{exportBU}_p < \text{rtm}_p$ to ensure no loss. + +## When to Use Which + +| Scenario | Recommended | +|----------|-------------| +| Intra-utility P2P (same DISCOM) | Min-of-two (simpler) | +| Inter-utility P2P (different DISCOMs) | **Deviation** (no coordination) | +| Regulatory requirement for energy tracing | Min-of-two | +| Revenue certainty for compliant parties | **Deviation** | + +--- + +# Appendix B: Detailed Optimality Analysis + +This appendix provides formal analysis of when the 3-round min-of-two allocation is suboptimal. + +## The Centralized Optimum + +If a central coordinator had all information, the optimal allocation maximizes total settlement: + +$$ +\begin{align} +\max_{a^B, a^S, z} \quad & \sum_{k \in \mathcal{T}} z_k \\ +\text{s.t.} \quad & z_k \leq a^B_k, \quad z_k \leq a^S_k & \forall k \\ +& \sum_{k: b(k)=i} a^B_k \leq m_i & \forall i \\ +& \sum_{k: s(k)=j} a^S_k \leq m_j & \forall j \\ +& 0 \leq a^B_k, a^S_k \leq \text{tr}_k & \forall k +\end{align} +$$ + +This is a **Linear Program (LP)** solvable in polynomial time. + +## Suboptimality Example: Cross-Linked Trades + +Consider this scenario with both-side shortfalls: + +``` +Trades: + T1: Buyer B1 ↔ Seller S1, quantity = 10 + T2: Buyer B1 ↔ Seller S2, quantity = 10 + T3: Buyer B2 ↔ Seller S1, quantity = 10 + +Meter readings: + B1 consumed = 15, B2 consumed = 10 + S1 produced = 15, S2 produced = 10 +``` + +**Pro-Rata Algorithm Result:** +- Seller allocations: S1 → T1=7.5, T3=7.5; S2 → T2=10 +- Buyer allocations: B1 → T1=7.5, T2=7.5; B2 → T3=10 +- Settlements: T1=min(7.5,7.5)=7.5, T2=min(10,7.5)=7.5, T3=min(7.5,10)=7.5 +- **Total settled: 22.5 kWh** + +**Optimal (LP Solution):** +- T1=5, T2=10, T3=10 +- Check: B1 uses 15 (5+10), B2 uses 10, S1 produces 15 (5+10), S2 produces 10 +- **Total settled: 25 kWh** + +**Gap:** 22.5/25 = 90% of optimal. + +## FIFO Can Be Worse + +With timestamp-based FIFO allocation (T1 < T2 < T3): + +- Round 1 (Sellers): S1 allocates T1=10, T3=5; S2 allocates T2=10 +- Round 2 (Buyers): B1 allocates T1=10, T2=5; B2 allocates T3=5 +- **Total settled: 20 kWh** (only 80% of optimal) + +## Theoretical Bounds + +**Worst-case approximation ratio:** The distributed algorithm achieves at least **67%** of optimal. + +**Tight example:** +``` +T1: B1 ↔ S1, quantity = 100 +T2: B1 ↔ S2, quantity = 100 +T3: B2 ↔ S1, quantity = 100 +Meters: B1=100, B2=100, S1=100, S2=100 + +FIFO (T1 first): T1=100, T2=0, T3=0 → 100 kWh +Optimal: T1=50, T2=50, T3=50 → 150 kWh +Ratio: 100/150 = 67% +``` + +**Practical performance:** In typical scenarios with mild, correlated shortfalls, the gap is much smaller (<10%). The 67% bound is a pathological worst case requiring: +- Both-side shortfalls +- Cross-linked bipartite trade graph +- Adversarial allocation order + +--- + +# Appendix C: Side-by-Side Method Comparison + +## Scenario + +``` +Trade: B1 (DISCOM-A) ↔ S1 (DISCOM-B) + - Contract: 100 kWh @ 6 INR/kWh = 600 INR + +Actuals: + - B1 consumed: 80 kWh (20 kWh underconsumption) + - S1 produced: 70 kWh (30 kWh underproduction) + +Rates: + - exportBU_p = 4 INR/kWh + - importSU_p = 8 INR/kWh + - Grid import = 10 INR/kWh +``` + +## Min-of-Two Result + +``` +Settlement = min(80, 70) = 70 kWh + +Buyer pays: + - P2P: 70 × 6 = 420 INR + - Grid: (80-70) × 10 = 100 INR + - Total: 520 INR for 80 kWh (6.50 INR/kWh effective) + +Seller receives: + - P2P: 70 × 6 = 420 INR + - Total: 420 INR for 70 kWh (6.00 INR/kWh effective) +``` + +## Deviation Result + +``` +Buyer pays: + - 100×6 - 20×4 = 520 INR (same) + +Seller receives: + - 100×6 - 30×8 = 360 INR (60 INR less) + +SU receives: 240 INR +BU pays: 80 INR +``` + +## Key Insight + +- **Buyer outcome:** Identical (520 INR) +- **Seller outcome:** Different + - Min-of-two: 420 INR + - Deviation: 360 INR (explicit penalty for 30 kWh shortfall) + +The deviation method penalizes the non-compliant party more explicitly, while min-of-two implicitly reduces settlement without explicit penalty attribution. + +## Principles Alignment + +| Principle | Min-of-Two | Deviation | +|-----------|------------|-----------| +| Shortfall responsibility | ✓ Implicit | ✓ Explicit | +| Independence | Partial (needs 3 rounds) | ✓ Full | +| Existing billing flows | ✓ | ✓ | +| No surprise for compliant | Partial | ✓ Full | +| Allocation-independent total | Partial | ✓ Full | + +Both methods satisfy the core principles; deviation provides stronger guarantees for independence and compliant-party protection at the cost of more explicit penalty accounting. diff --git a/docs/implementation-guides/v2/P2P_Trading/note-on-payment-in-p2p-trading-interdiscom.md b/docs/implementation-guides/v2/P2P_Trading/note-on-payment-in-p2p-trading-interdiscom.md new file mode 100644 index 00000000..85ba3aff --- /dev/null +++ b/docs/implementation-guides/v2/P2P_Trading/note-on-payment-in-p2p-trading-interdiscom.md @@ -0,0 +1,1621 @@ +# Payment Design for Inter-Utility Peer to Peer Energy Trading + +Version 0.1 (Non-Normative) + +## Table of contents +- [1. Overview](#1-overview) +- [2. Design Principles](#2-design-principles) + - [2.1. Peer-to-Peer Transparency](#21-peer-to-peer-transparency) + - [2.2. Bill Component Transparency](#22-bill-component-transparency) + - [2.3. Settlement Flow](#23-settlement-flow) +- [3. Sequence Diagram](#3-sequence-diagram) +- [4. Payment Status Lifecycle](#4-payment-status-lifecycle) +- [5. Bill Components](#5-bill-components) +- [6. Message Flow Examples](#6-message-flow-examples) + - [6.1. on\_select: Bill Breakdown + Accepted Payment Methods](#61-on_select-bill-breakdown--accepted-payment-methods) + - [6.2. on\_init: Payment Terms Confirmation](#62-on_init-payment-terms-confirmation) + - [6.3. confirm: Payment Authorization](#63-confirm-payment-authorization) + - [6.4. on\_update: Final Invoice (After Allocation)](#64-on_update-final-invoice-after-allocation) + - [6.5. on\_update: Partial Delivery (Curtailment)](#65-on_update-partial-delivery-curtailment) + - [6.6. on\_update: Settlement Complete](#66-on_update-settlement-complete) + - [6.7. on\_status: Trade Completed](#67-on_status-trade-completed) +- [7. Key Design Decisions](#7-key-design-decisions) + - [7.1. Why Platform-to-Platform Settlement?](#71-why-platform-to-platform-settlement) + - [7.2. Customer Agency](#72-customer-agency) + - [7.3. Discom's Role](#73-discoms-role) +- [8. Implementation Notes](#8-implementation-notes) + - [8.1. For Buyer Platforms (BAP)](#81-for-buyer-platforms-bap) + - [8.2. For Seller Platforms (BPP)](#82-for-seller-platforms-bpp) + +## 1. Overview + +This note documents the payment flow design for peer-to-peer energy trading across distribution companies (discoms). While trading platforms act as intermediaries facilitating transactions, the fundamental nature remains **peer-to-peer**: energy flows from one prosumer to another consumer, and payment should reflect this direct relationship. + +## 2. Design Principles + +### 2.1. Peer-to-Peer Transparency + +Even though payments flow through platforms (BAP → BPP), the underlying transaction is between two individuals: +- **Seller (Prosumer)**: Generates excess energy and sells it +- **Buyer (Consumer)**: Purchases energy from the seller + +Platforms act with **delegated agency** on behalf of their customers. This means: +- Customers must have **full visibility** into all transaction components +- All fees (both buyer and seller platform fees) must be disclosed upfront +- In future implementations, it is conceivable that customers may **pay sellers directly** + +### 2.2. Bill Component Transparency + +At the selection stage (`on_select`), buyers must see the complete cost breakdown: +- **Energy value**: The actual cost of energy (quantity × price per unit) +- **Buyer platform fee**: Fee charged by the buyer's platform +- **Seller platform fee**: Fee charged by the seller's platform +- Optionally platforms can also indicate the wheeling charges & deviation penaly that utility will bill seperately, outside this p2p transaction. That will give customers a full picture of all opportunity costs involved in engaging in a trade. + +This ensures informed consent before the trade is confirmed. + +### 2.3. Settlement Flow + +The payment settlement follows a clear progression: +1. **Authorization**: Buyer platform verifies wallet balance or credit line covers total amount +2. **Allocation**: After energy delivery is confirmed via meter readings +3. **Final Invoice**: Seller platform raises invoice with receiving account details +4. **Settlement**: Money moves from buyer platform to seller platform, then to seller + +## 3. Sequence Diagram + +```mermaid +sequenceDiagram + participant Buyer + participant BuyerPlatform as Buyer Platform (BAP) + participant SellerPlatform as Seller Platform (BPP) + participant Seller + + Note over Buyer, Seller: Discovery & Selection Phase + Buyer->>BuyerPlatform: Select energy offer + BuyerPlatform->>SellerPlatform: select + SellerPlatform-->>BuyerPlatform: on_select (bill breakdown + accepted payment methods) + BuyerPlatform-->>Buyer: Show total: energy + buyer fee + seller fee + + Note over Buyer, Seller: Initialization Phase + Buyer->>BuyerPlatform: Confirm intent to buy + BuyerPlatform->>BuyerPlatform: Check wallet/credit >= total amount + BuyerPlatform->>SellerPlatform: init (with BAP settlement account) + SellerPlatform-->>BuyerPlatform: on_init (both settlement accounts + accepted methods) + + Note over Buyer, Seller: Confirmation Phase + BuyerPlatform->>BuyerPlatform: Reserve funds from wallet + BuyerPlatform->>SellerPlatform: confirm + SellerPlatform-->>BuyerPlatform: on_confirm (payment AUTHORIZED) + + Note over Buyer, Seller: Energy Delivery Phase + Seller->>SellerPlatform: Energy injected to grid + SellerPlatform->>SellerPlatform: Record meter readings + SellerPlatform-->>BuyerPlatform: on_update (delivery progress) + + Note over Buyer, Seller: Settlement Phase + SellerPlatform->>SellerPlatform: Allocation complete + SellerPlatform-->>BuyerPlatform: on_update (final invoice + seller account + tracking URL) + BuyerPlatform->>BuyerPlatform: Deduct buyer platform fee + BuyerPlatform->>SellerPlatform: Transfer (energy value + seller fee) + SellerPlatform->>SellerPlatform: Deduct seller platform fee + SellerPlatform->>Seller: Transfer energy value + SellerPlatform-->>BuyerPlatform: on_update (payment SETTLED) + BuyerPlatform-->>Buyer: Trade complete notification +``` + +## 4. Payment Status Lifecycle + +| Status | When | Meaning | +|--------|------|---------| +| `PENDING` | on_select | Awaiting buyer decision | +| `INITIATED` | init | Payment process started | +| `AUTHORIZED` | on_init → on_confirm | Funds reserved, trade approved | +| `ADJUSTED` | on_update (curtailment) | Amount changed due to partial delivery | +| `SETTLED` | on_update (complete) | Money transferred to all parties | + +## 5. Bill Components + +The `beckn:orderValue` object provides full transparency: + +```json +{ + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "description": "Seller platform fee (3%)" + } + ] +} +``` + +## 6. Message Flow Examples + +### 6.1. on_select: Bill Breakdown + Accepted Payment Methods + +At selection, the seller platform returns the complete bill breakdown and accepted payment methods, enabling the buyer to make an informed decision. + +
+on_select Response + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_select", + "timestamp": "2024-10-04T10:15:05Z", + "message_id": "msg-on-select-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:paymentStatus": "PENDING", + "beckn:acceptedPaymentMethod": ["UPI", "BANK_TRANSFER", "WALLET"] + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ] + } + } +} + +``` +
+ +### 6.2. on_init: Payment Terms Confirmation + +The initialization response confirms both settlement accounts and accepted payment methods. + +
+on_init Response + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "timestamp": "2024-10-04T10:20:05Z", + "message_id": "msg-on-init-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:acceptedPaymentMethod": ["UPI", "BANK_TRANSFER", "WALLET"], + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "bap.energy-consumer.com", + "accountHolderName": "Energy Consumer BAP Pvt Ltd", + "accountNumber": "1234567890", + "ifscCode": "HDFC0001234", + "bankName": "HDFC Bank", + "vpa": "energy-consumer@upi" + }, + { + "beneficiaryId": "bpp.energy-provider.com", + "accountHolderName": "Solar Farm Energy Provider Pvt Ltd", + "accountNumber": "9876543210", + "ifscCode": "ICICI0005678", + "bankName": "ICICI Bank", + "vpa": "solar-provider@upi" + } + ] + } + } + } + } +} + +``` +
+ +### 6.3. confirm: Payment Authorization + +The confirmation request contains minimal payment info - just the authorized amount. Full settlement details were already exchanged. + +
+confirm Request + +```json +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "timestamp": "2024-10-04T10:25:00Z", + "message_id": "msg-confirm-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED" + } + } + } +} + +``` +
+ +### 6.4. on_update: Final Invoice (After Allocation) + +After energy allocation is complete, the seller platform raises the final invoice with: +- Final amounts based on actual delivered quantities +- Seller's settlement account for payment +- Payment tracking URL for transparency + +
+on_update Final Invoice + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T18:15:00Z", + "message_id": "msg-on-update-final-invoice-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "INPROGRESS", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 15.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 15.0, + "allocatedEnergy": 15.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T18:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T12:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 10.0, + "allocatedEnergy": 10.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T18:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED", + "beckn:acceptedPaymentMethod": ["UPI", "BANK_TRANSFER"], + "beckn:paymentURL": "https://payments.seller-platform.com/track?txn=TXN-ENERGY-001", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "bpp.energy-provider.com", + "accountHolderName": "Solar Farm Energy Provider Pvt Ltd", + "accountNumber": "9876543210", + "ifscCode": "ICICI0005678", + "bankName": "ICICI Bank", + "vpa": "solar-provider@upi" + } + ] + } + } + } + } +} + +``` +
+ +### 6.5. on_update: Partial Delivery (Curtailment) + +If delivery is curtailed (e.g., grid outage), the payment amount is adjusted to reflect actual delivered energy. + +
+on_update Curtailment + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T14:30:00Z", + "message_id": "msg-on-update-curtailment-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "INPROGRESS", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 8.5, + "curtailedQuantity": 6.5, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 8.5, + "allocatedEnergy": 8.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 1.36, + "components": [ + { + "type": "UNIT", + "value": 1.28, + "currency": "USD", + "description": "Energy value for delivered quantity (8.5 kWh × $0.15)" + }, + { + "type": "FEE", + "value": 0.03, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.04, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 1.36 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "ADJUSTED" + } + } + } +} + +``` +
+ +### 6.6. on_update: Settlement Complete + +Once money has moved from buyer platform to seller platform (tracked via URL), the seller platform marks the trade complete. + +
+on_update Settlement Complete + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T18:45:00Z", + "message_id": "msg-on-update-settlement-complete-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "COMPLETED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": ["energy-resource-solar-001"] + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": ["energy-resource-solar-001"] + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "SETTLED", + "beckn:paidAt": "2024-10-04T18:40:00Z", + "beckn:txnRef": "TXN-ENERGY-001-SETTLED" + } + } + } +} + +``` +
+ +### 6.7. on_status: Trade Completed + +Final status shows the order and payment as complete. + +
+on_status Completed + +```json +{ + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T18:30:00Z", + "message_id": "msg-on-status-completed-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "COMPLETED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 15.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + }, + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T09:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T12:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T12:00:00Z", + "schema:endTime": "2024-10-04T15:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 5.0, + "allocatedEnergy": 5.0, + "unit": "kWh" + }, + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T15:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 5.0, + "allocatedEnergy": 5.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T18:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "SETTLED", + "beckn:paidAt": "2024-10-04T19:00:00Z" + } + } + } +} + +``` +
+ +## 7. Key Design Decisions + +### 7.1. Why Platform-to-Platform Settlement? + +While the trade is peer-to-peer, platform-to-platform settlement provides: +1. **Credit management**: Platforms can extend goodwill credit to customers +2. **Wallet management**: Customers can pre-fund wallets for faster trades +3. **Dispute resolution**: Platforms can mediate if issues arise +4. **Regulatory compliance**: Platforms handle KYC/AML requirements + +### 7.2. Customer Agency + +Despite platform intermediation: +- **Full visibility**: All fees and amounts are disclosed in every message +- **Settlement transparency**: Tracking URLs allow customers to verify fund movement +- **Future optionality**: The protocol supports direct peer-to-peer payment in future versions +- **Choice of platform**: Customers can choose platforms based on fees and services + +### 7.3. Discom's Role + +Discoms (distribution companies) are privy to: +- **Trade volumes only**: For grid management and wheeling fee calculation +- **Wheeling fees**: Charged separately in monthly utility bills +- **No double billing**: Peer-traded energy is excluded from regular consumption billing + +## 8. Implementation Notes + +### 8.1. For Buyer Platforms (BAP) + +1. **Before confirm**: Verify `wallet_balance + goodwill_credit >= total_amount` +2. **On final invoice**: Validate bill components match original on_select +3. **Settlement**: Deduct buyer fee, transfer remainder to seller platform +4. **Tracking**: Monitor payment URL until SETTLED status received + +### 8.2. For Seller Platforms (BPP) + +1. **On select**: Return complete bill breakdown with all fees +2. **On init**: Provide settlement account details +3. **After allocation**: Raise final invoice with tracking URL +4. **On payment receipt**: Deduct seller fee, pay seller, send SETTLED status + +--- + +*This design ensures that while platforms facilitate the transaction, customers remain the principals in a true peer-to-peer energy trade.* diff --git a/docs/implementation-guides/v2/P2P_Trading/taxonomy.md b/docs/implementation-guides/v2/P2P_Trading/taxonomy.md deleted file mode 100644 index f060747f..00000000 --- a/docs/implementation-guides/v2/P2P_Trading/taxonomy.md +++ /dev/null @@ -1,253 +0,0 @@ -# P2P Energy Trading Taxonomy Reference - -## Overview - -This document provides a comprehensive reference for all enumerations and taxonomies used in P2P Energy Trading schemas. - -## Energy Source Types - -**Schema**: `EnergyResource.sourceType`, `EnergyTradeContract.sourceType` - -| Value | Description | Use Case | -|-------|-------------|----------| -| `SOLAR` | Solar photovoltaic energy | Solar panels, rooftop solar | -| `BATTERY` | Battery storage energy | Battery systems, energy storage | -| `GRID` | Grid-sourced energy | Traditional utility grid | -| `HYBRID` | Hybrid energy source | Combination of multiple sources | -| `RENEWABLE` | Renewable energy (unspecified) | General renewable energy category | - -**Notes**: -- Source type influences pricing but not workflow -- Source verification occurs at onboarding but can change post-onboarding -- Example: Switching from solar to diesel backup - -## Delivery Modes - -**Schema**: `EnergyResource.deliveryMode`, `EnergyTradeDelivery.deliveryMode` - -| Value | Description | Use Case | -|-------|-------------|----------| -| `EV_CHARGING` | Electric vehicle charging | Direct EV charging | -| `BATTERY_SWAP` | Battery swap service | Battery exchange stations | -| `V2G` | Vehicle-to-Grid | EVs feeding energy back to grid | -| `GRID_INJECTION` | Grid injection | Energy injected into utility grid | - -**Notes**: -- Used as discovery filter to match consumer requirements -- Determines delivery mechanism for energy transfer - -## Pricing Models - -**Schema**: `EnergyTradeOffer.pricingModel` - -| Value | Description | Use Case | -|-------|-------------|----------| -| `PER_KWH` | Per kilowatt-hour pricing | Standard energy pricing | -| `TIME_OF_DAY` | Time-of-day pricing | Variable rates by time period | -| `SUBSCRIPTION` | Subscription-based pricing | Fixed monthly/annual pricing | -| `FIXED` | Fixed price | Flat rate pricing | - -**Notes**: -- `TIME_OF_DAY` requires `timeOfDayRates` array -- `PER_KWH` is most common for P2P energy trading - -## Settlement Types - -**Schema**: `EnergyTradeOffer.settlementType` - -| Value | Description | Frequency | Use Case | -|-------|-------------|-----------|----------| -| `REAL_TIME` | Real-time settlement | Continuous | Instant payment processing | -| `HOURLY` | Hourly settlement | Every hour | High-frequency trading | -| `DAILY` | Daily settlement | Once per day | Standard P2P trading | -| `WEEKLY` | Weekly settlement | Once per week | Long-term contracts | -| `MONTHLY` | Monthly settlement | Once per month | Subscription-based trading | - -**Notes**: -- Determines when payments are processed -- Default: `DAILY` (see profile.json) -- Settlement cycles tracked in `EnergyTradeContract.settlementCycles` - -## Contract Status - -**Schema**: `EnergyTradeContract.contractStatus` - -| Value | Description | Lifecycle Stage | -|-------|-------------|-----------------| -| `PENDING` | Contract pending activation | After init, before confirm | -| `ACTIVE` | Contract is active | After confirm, during fulfillment | -| `COMPLETED` | Contract completed | After successful fulfillment | -| `TERMINATED` | Contract terminated | Cancelled or failed | - -**Notes**: -- Decouples trade from fulfillment -- Generator, transmitter, and consumer operate independently -- Status progression: PENDING → ACTIVE → COMPLETED - -## Delivery Status - -**Schema**: `EnergyTradeDelivery.deliveryStatus` - -| Value | Description | Stage | -|-------|-------------|-------| -| `PENDING` | Delivery pending | Before delivery starts | -| `IN_PROGRESS` | Delivery in progress | Active energy transfer | -| `COMPLETED` | Delivery completed | Successful completion | -| `FAILED` | Delivery failed | Failed or cancelled | - -**Notes**: -- Handles recurring or continuous fulfillment scenarios -- Multiple deliveries can be tied to a single contract -- Status updates as meter readings arrive - -## Settlement Cycle Status - -**Schema**: `EnergyTradeContract.settlementCycles[].status` - -| Value | Description | Stage | -|-------|-------------|-------| -| `PENDING` | Settlement pending | Awaiting settlement | -| `SETTLED` | Settlement completed | Payment processed | -| `FAILED` | Settlement failed | Payment processing failed | - -**Notes**: -- Each settlement cycle tracks its own status -- Status updates when settlement is processed -- Failed settlements may be retried - -## Billing Cycle Status - -**Schema**: `EnergyTradeContract.billingCycles[].status` - -| Value | Description | Stage | -|-------|-------------|-------| -| `PENDING` | Billing pending | Awaiting payment | -| `PAID` | Payment received | Payment completed | -| `OVERDUE` | Payment overdue | Payment past due date | - -**Notes**: -- Supports ongoing connections billed periodically -- Multiple billing cycles per contract -- Status updates when payment is received - -## Telemetry Metric Names - -**Schema**: `EnergyTradeDelivery.telemetry[].metrics[].name` - -| Value | Description | Unit Code | Use Case | -|-------|-------------|-----------|----------| -| `ENERGY` | Energy delivered | `KWH` | Total energy in kilowatt-hours | -| `POWER` | Power level | `KW` | Instantaneous power in kilowatts | -| `FLOW_RATE` | Energy flow rate | `KW` | Rate of energy transfer | -| `VOLTAGE` | Voltage level | `VLT` | Grid voltage in volts | -| `CURRENT` | Current level | `AMP` | Current in amperes | -| `FREQUENCY` | Frequency | `HZ` | Grid frequency in hertz | -| `POWER_QUALITY` | Power quality metric | dimensionless | Power quality indicator | - -**Notes**: -- All metrics use `schema:QuantitativeValue` structure -- Unit codes must match metric type -- Update frequency: Every 5-15 minutes during active delivery - -## Payment Types - -**Schema**: Core `Payment.type` (not in Energy* schemas) - -| Value | Description | Timing | -|-------|-------------|--------| -| `PRE-ORDER` | Payment before order | Before order confirmation | -| `ON-FULFILLMENT` | Payment during fulfillment | During energy delivery | -| `POST-FULFILLMENT` | Payment after fulfillment | After delivery completion | - -**Notes**: -- Defined in core Payment schema -- Most common for energy trading: `ON-FULFILLMENT` - -## Payment Status - -**Schema**: Core `Payment.status` (not in Energy* schemas) - -| Value | Description | -|-------|-------------| -| `PAID` | Payment received | -| `NOT-PAID` | Payment not yet received | - -## Payment Collected By - -**Schema**: Core `Payment.collected_by` (not in Energy* schemas) - -| Value | Description | -|-------|-------------| -| `BAP` | Collected by Buyer App Platform | -| `BPP` | Collected by Provider Platform | - -**Notes**: -- BPP collection is most common for energy trading -- BAP collection requires pre-payment - -## Fulfillment Stop Types - -**Schema**: Core `Stop.type` (not in Energy* schemas) - -| Value | Description | Required Fields | -|-------|-------------|-----------------| -| `START` | Source location | `location.address` (source meter ID) | -| `END` | Target location | `location.address` (target meter ID) | - -**Notes**: -- At least one END stop is required -- Meter IDs in `location.address` use IEEE mRID format -- START stop: Source meter (generator) -- END stop: Target meter (consumer) - -## Certification Status Examples - -**Schema**: `EnergyResource.certificationStatus` (free-form string) - -Common values: -- `"Carbon Offset Certified"` -- `"Green Energy Certified"` -- `"Renewable Energy Certified"` -- `"ISO 14001 Certified"` - -**Notes**: -- Free-form string (not an enum) -- Used for compliance and marketing -- Detailed certificates in `sourceVerification.certificates` - -## Unit Codes - -**Schema**: `EnergyTradeDelivery.telemetry[].metrics[].unitCode` - -| Metric | Unit Code | Description | -|--------|-----------|-------------| -| `ENERGY` | `KWH` | Kilowatt-hours | -| `POWER` | `KW` | Kilowatts | -| `FLOW_RATE` | `KW` | Kilowatts | -| `VOLTAGE` | `VLT` | Volts | -| `CURRENT` | `AMP` | Amperes | -| `FREQUENCY` | `HZ` | Hertz | -| `POWER_QUALITY` | (dimensionless) | No unit | - -## Summary Table - -| Category | Enum Values | Schema Location | -|----------|-------------|----------------| -| Energy Source Types | SOLAR, BATTERY, GRID, HYBRID, RENEWABLE | `EnergyResource.sourceType`, `EnergyTradeContract.sourceType` | -| Delivery Modes | EV_CHARGING, BATTERY_SWAP, V2G, GRID_INJECTION | `EnergyResource.deliveryMode`, `EnergyTradeDelivery.deliveryMode` | -| Pricing Models | PER_KWH, TIME_OF_DAY, SUBSCRIPTION, FIXED | `EnergyTradeOffer.pricingModel` | -| Settlement Types | REAL_TIME, HOURLY, DAILY, WEEKLY, MONTHLY | `EnergyTradeOffer.settlementType` | -| Contract Status | PENDING, ACTIVE, COMPLETED, TERMINATED | `EnergyTradeContract.contractStatus` | -| Delivery Status | PENDING, IN_PROGRESS, COMPLETED, FAILED | `EnergyTradeDelivery.deliveryStatus` | -| Settlement Cycle Status | PENDING, SETTLED, FAILED | `EnergyTradeContract.settlementCycles[].status` | -| Billing Cycle Status | PENDING, PAID, OVERDUE | `EnergyTradeContract.billingCycles[].status` | -| Telemetry Metrics | ENERGY, POWER, FLOW_RATE, VOLTAGE, CURRENT, FREQUENCY, POWER_QUALITY | `EnergyTradeDelivery.telemetry[].metrics[].name` | - -## Usage Guidelines - -1. **Enum Values**: Always use uppercase with underscores (e.g., `SOLAR`, `GRID_INJECTION`) -2. **Case Sensitivity**: Enum values are case-sensitive -3. **Validation**: Validate enum values against this taxonomy -4. **Extensibility**: Do not add custom enum values; use free-form strings for extensions -5. **Documentation**: Document any custom values used in certification status or other free-form fields - diff --git a/examples/enrollment/v2/README.md b/examples/enrollment/v2/README.md new file mode 100644 index 00000000..c2f03752 --- /dev/null +++ b/examples/enrollment/v2/README.md @@ -0,0 +1,53 @@ +# Enrollment Examples + +This directory contains JSON examples for the enrollment/onboarding flow for Digital Energy Programs. + +## Files + +### Init Requests +- **init-request-simple-consumer.json** - Simple consumer with single meter enrolling in a demand flexibility program +- **init-request-prosumer-solar-battery.json** - Prosumer with solar and battery DERs enrolling in a P2P trading program + +### On_Init Responses +- **on-init-response-success.json** - Successful credential verification with no conflicts +- **on-init-response-conflict.json** - Enrollment conflict detected (meter already enrolled) +- **on-init-response-error.json** - Credential verification failed + +### Confirm Request +- **confirm-request.json** - Confirm request with enrollment start and end dates + +### On_Confirm Response +- **on-confirm-response-success.json** - Successful enrollment with issued credential + +### Update Requests (Revocation/Unenrollment) +- **update-request-consent-revocation.json** - Request to revoke a consent credential +- **update-request-unenrollment.json** - Request to unenroll from a program + +### On_Update Responses +- **on-update-response-consent-revocation.json** - Confirmation of consent revocation with status list details +- **on-update-response-unenrollment.json** - Confirmation of unenrollment with all credential revocations + +## Usage + +These examples are embedded in the implementation guide using the `embed_example_json.py` script. The examples are referenced using `
` blocks in the markdown file. + +To update the embedded examples in the guide, run: +```bash +python3 scripts/embed_example_json.py docs/implementation-guides/v2/Onboarding/IG_Onboarding_users_in_digital_energy_programs.md +``` + +## Schema + +All examples use the `EnergyEnrollment` schema defined at: +- Context: `https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld` +- Attributes: `../protocol-specifications-new/schema/EnergyEnrollment/v0.2/attributes.yaml` + +## Revocation Mechanism + +Consent and enrollment credentials use W3C VC Status Lists (BitstringStatusList) for revocation: + +1. **Consent Revocation**: User revokes consent via `update` action → BPP updates status list → Future verifications fail +2. **Unenrollment**: User unenrolls via `update` action → BPP revokes enrollment VC and all consent VCs → All credentials added to status lists + +Verifiers must check status lists before accepting credentials. Status lists use bitstrings for efficient and privacy-preserving revocation checks as per [W3C VC Data Model v2.0](https://www.w3.org/TR/vc-data-model-2.0/). + diff --git a/examples/enrollment/v2/confirm-request-oauth2.json b/examples/enrollment/v2/confirm-request-oauth2.json new file mode 100644 index 00000000..13c02e70 --- /dev/null +++ b/examples/enrollment/v2/confirm-request-oauth2.json @@ -0,0 +1,58 @@ +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:00Z", + "message_id": "msg-confirm-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwiYXVkIjoicHJvZ3JhbS1vd25lci1icHAiLCJpc3MiOiJodHRwczovL3V0aWxpdHktaWRwLmV4YW1wbGUuY29tIiwiaWF0IjoxNzI5MDAwMDAwLCJleHAiOjE3MjkwMDM2MDB9.signature" + }, + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z" + } + } + } +} diff --git a/examples/enrollment/v2/confirm-request-otp.json b/examples/enrollment/v2/confirm-request-otp.json new file mode 100644 index 00000000..0204645b --- /dev/null +++ b/examples/enrollment/v2/confirm-request-otp.json @@ -0,0 +1,62 @@ +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:33:00Z", + "message_id": "msg-confirm-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "mobile": "+919999999999", + "nguid": "LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm", + "otp": "123456", + "utilityCustomerId": "CUST-123456", + "userType": "CONSUMER" + }, + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z" + } + } + } +} diff --git a/examples/enrollment/v2/confirm-request.json b/examples/enrollment/v2/confirm-request.json new file mode 100644 index 00000000..eb0338e5 --- /dev/null +++ b/examples/enrollment/v2/confirm-request.json @@ -0,0 +1,60 @@ +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:00Z", + "message_id": "msg-confirm-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "consents": [ + { + "type": "DATA_COLLECTION", + "granted": true, + "grantedAt": "2024-10-15T10:33:00Z", + "description": "Consent to collect and share meter data for program participation" + }, + { + "type": "DER_CONTROL", + "granted": false, + "description": "Consent to control DER devices for demand response (not applicable for this enrollment)" + } + ] + } + } + } +} diff --git a/examples/enrollment/v2/init-request-oauth2.json b/examples/enrollment/v2/init-request-oauth2.json new file mode 100644 index 00000000..2eaa814f --- /dev/null +++ b/examples/enrollment/v2/init-request-oauth2.json @@ -0,0 +1,53 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:00Z", + "message_id": "msg-init-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwiYXVkIjoicHJvZ3JhbS1vd25lci1icHAiLCJpc3MiOiJodHRwczovL3V0aWxpdHktaWRwLmV4YW1wbGUuY29tIiwiaWF0IjoxNzI5MDAwMDAwLCJleHAiOjE3MjkwMDM2MDB9.signature", + "idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwibmFtZSI6IlJhamVzaCBLdW1hciIsImVtYWlsIjoicmFqZXNoQGV4YW1wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly91dGlsaXR5LWlkcC5leGFtcGxlLmNvbSIsImlhdCI6MTcyOTAwMDAwMCwiZXhwIjoxNzI5MDAzNjAwfQ.signature" + }, + "customer": { + "name": "Rajesh Kumar" + } + } + } + } +} diff --git a/examples/enrollment/v2/init-request-otp.json b/examples/enrollment/v2/init-request-otp.json new file mode 100644 index 00000000..a9f40c9c --- /dev/null +++ b/examples/enrollment/v2/init-request-otp.json @@ -0,0 +1,54 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:00Z", + "message_id": "msg-init-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "mobile": "+919999999999", + "utilityCustomerId": "CUST-123456", + "userType": "CONSUMER" + }, + "customer": { + "name": "Rajesh Kumar" + } + } + } + } +} diff --git a/examples/enrollment/v2/init-request-prosumer-solar-battery.json b/examples/enrollment/v2/init-request-prosumer-solar-battery.json new file mode 100644 index 00000000..2aaf897a --- /dev/null +++ b/examples/enrollment/v2/init-request-prosumer-solar-battery.json @@ -0,0 +1,81 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T11:00:00Z", + "message_id": "msg-init-prosumer-001", + "transaction_id": "txn-onboard-prosumer-001", + "bap_id": "ea-portal.example.com", + "bap_uri": "https://ea-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-prosumer-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-p2p-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:prosumer-789" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-vpp-p2p-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-prosumer-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING", + "beckn:deliveryAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "meters": [ + { + "meterId": "umid-002", + "utilityId": "utility-example-001" + } + ], + "ders": [ + { + "derId": "der-solar-001", + "type": "SOLAR_PV", + "capacityValue": 10.0, + "capacityUnit": "kW" + }, + { + "derId": "der-battery-001", + "type": "BATTERY_STORAGE", + "capacityValue": 15.0, + "capacityUnit": "kWh" + } + ] + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "mobile": "+919876543210", + "userType": "PROSUMER" + }, + "meterOwnershipCredential": { + "credentialId": "vc-meter-ownership-002", + "type": "MeterOwnershipCredential", + "format": "VC-JWT", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + "verificationUrl": "https://utility-example-001.com/verify/vc-meter-ownership-002" + } + } + } + } +} diff --git a/examples/enrollment/v2/init-request-simple-consumer.json b/examples/enrollment/v2/init-request-simple-consumer.json new file mode 100644 index 00000000..e21db683 --- /dev/null +++ b/examples/enrollment/v2/init-request-simple-consumer.json @@ -0,0 +1,67 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:00Z", + "message_id": "msg-init-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING", + "beckn:deliveryAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "customer": { + "name": "Rajesh Kumar", + "email": "rajesh.kumar@example.com" + }, + "meters": [ + { + "meterId": "umid-001", + "utilityId": "utility-example-001" + } + ], + "ders": [] + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "meterOwnershipCredential": { + "credentialId": "vc-meter-ownership-001", + "type": "MeterOwnershipCredential", + "format": "VC-JWT", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiTWV0ZXJPd25lcnNoaXBDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6dXNlci0xMjM0NSIsIm1ldGVySWQiOiJ1bWlkLTAwMSIsInV0aWxpdHlJZCI6InV0aWxpdHktZXhhbXBsZS0wMDEiLCJvd25lcnNoaXBTdGF0dXMiOiJPV05FUiIsInZhbGlkRnJvbSI6IjIwMjQtMDEtMDFUMDA6MDA6MDBaIiwidmFsaWRVbnRpbCI6IjIwMjUtMTItMzFUMjM6NTk6NTlaIn19LCJpc3MiOiJkaWQ6ZXhhbXBsZTp1dGlsaXR5LWNyZWRlbnRpYWwtaXNzdWVyIiwiaWF0IjoxNzA0MDY3MjAwfQ.signature", + "verificationUrl": "https://utility-example-001.com/verify/vc-meter-ownership-001" + } + } + } + } +} diff --git a/examples/enrollment/v2/on-confirm-response-no-meter.json b/examples/enrollment/v2/on-confirm-response-no-meter.json new file mode 100644 index 00000000..74d14ec0 --- /dev/null +++ b/examples/enrollment/v2/on-confirm-response-no-meter.json @@ -0,0 +1,64 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:05Z", + "message_id": "msg-on-confirm-no-meter-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "FAILED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + } + } + }, + "error": { + "code": "BIZ_NO_METER_SPECIFIED", + "message": "No meter specified for enrollment. Please select from available meters.", + "details": { + "path": "$.message.order.orderAttributes.meters", + "availableMeters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "address": "123 Main Street, Bangalore", + "sanctionedLoad": 5.0, + "connectionType": "residential" + }, + { + "meterId": "umid-002", + "meterNumber": "MTR-987654322", + "address": "456 Oak Avenue, Bangalore", + "sanctionedLoad": 10.0, + "connectionType": "commercial" + } + ] + } + } +} diff --git a/examples/enrollment/v2/on-confirm-response-oauth2.json b/examples/enrollment/v2/on-confirm-response-oauth2.json new file mode 100644 index 00000000..dbb7cc4d --- /dev/null +++ b/examples/enrollment/v2/on-confirm-response-oauth2.json @@ -0,0 +1,86 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:05Z", + "message_id": "msg-on-confirm-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:orderNumber": "ENR-2024-OAUTH-001234", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "verified": true, + "verifiedAt": "2024-10-15T10:35:05Z", + "subject": "user-12345", + "issuer": "https://utility-idp.example.com", + "message": "Token verified successfully" + }, + "enrollmentId": "enrollment-oauth2-001", + "status": "ACTIVE", + "programId": "program-p2p-trading-001", + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "sanctionedLoad": 5.0, + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "enrolledAt": "2024-10-15T10:35:05Z", + "loggedAt": "2024-10-15T10:35:05Z", + "logReference": "log-enrollment-oauth2-001", + "credential": { + "credentialId": "vc:enrollment:oauth2-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialUrl": "https://vpp-program-owner.example.com/credentials/vc:enrollment:oauth2-001", + "verificationUrl": "https://vpp-program-owner.example.com/verify/vc:enrollment:oauth2-001", + "issuedAt": "2024-10-15T10:35:05Z" + }, + "p2pdetails": { + "usertype": "consumer", + "isp2pactive": true, + "iscaactive": false, + "meternumber": "MTR-987654321", + "sdload": "5.0", + "cuflimit": "10.0" + } + } + } + } +} diff --git a/examples/enrollment/v2/on-confirm-response-otp.json b/examples/enrollment/v2/on-confirm-response-otp.json new file mode 100644 index 00000000..3ff6345f --- /dev/null +++ b/examples/enrollment/v2/on-confirm-response-otp.json @@ -0,0 +1,85 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:33:05Z", + "message_id": "msg-on-confirm-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:orderNumber": "ENR-2024-OTP-001234", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "verified": true, + "verifiedAt": "2024-10-15T10:33:05Z", + "message": "OTP verification successful", + "utilityCustomerId": "CUST-123456" + }, + "enrollmentId": "enrollment-otp-001", + "status": "ACTIVE", + "programId": "program-p2p-trading-001", + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "sanctionedLoad": 5.0, + "connectionType": "residential" + } + ], + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "enrolledAt": "2024-10-15T10:33:05Z", + "loggedAt": "2024-10-15T10:33:05Z", + "logReference": "log-enrollment-otp-001", + "credential": { + "credentialId": "vc:enrollment:otp-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialUrl": "https://vpp-program-owner.example.com/credentials/vc:enrollment:otp-001", + "verificationUrl": "https://vpp-program-owner.example.com/verify/vc:enrollment:otp-001", + "issuedAt": "2024-10-15T10:33:05Z" + }, + "p2pdetails": { + "usertype": "prosumer", + "isp2pactive": true, + "iscaactive": false, + "meternumber": "MTR-987654321", + "sdload": "5.0", + "cuflimit": "10.0" + } + } + } + } +} diff --git a/examples/enrollment/v2/on-confirm-response-success.json b/examples/enrollment/v2/on-confirm-response-success.json new file mode 100644 index 00000000..d102770a --- /dev/null +++ b/examples/enrollment/v2/on-confirm-response-success.json @@ -0,0 +1,67 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:35:05Z", + "message_id": "msg-on-confirm-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:orderNumber": "ENR-2024-001234", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED", + "beckn:deliveryAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credential": { + "credentialId": "vc:enrollment:consumer-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialUrl": "https://vpp-program-owner.example.com/credentials/vc:enrollment:consumer-001", + "verificationUrl": "https://vpp-program-owner.example.com/verify/vc:enrollment:consumer-001", + "issuedAt": "2024-10-15T10:35:05Z", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUHJvZ3JhbUVucm9sbG1lbnRDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6dXNlci0xMjM0NSIsImVucm9sbG1lbnRJZCI6ImVucm9sbG1lbnQtY29uc3VtZXItMDAxIiwicHJvZ3JhbUlkIjoicHJvZ3JhbS1mbGV4LWRlbWFuZC1yZXNwb25zZS0wMDEiLCJtZXRlcnMiOlsidW1pZC0wMDEiXSwic3RhdHVzIjoiQUNUSVZFIiwic3RhcnREYXRlIjoiMjAyNC0xMS0wMVQwMDowMDowMFoiLCJlbmREYXRlIjoiMjAyNS0xMC0zMVQyMzo1OTo1OVoifSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0xMC0xNVQxMDozNTowNVoiLCJleHBpcmF0aW9uRGF0ZSI6IjIwMjUtMTAtMzFUMjM6NTk6NTlaIn0sImlzcyI6ImRpZDpleGFtcGxlOnZwcC1wcm9ncmFtLW93bmVyIiwiaWF0IjoxNzI5MDk3NzA1fQ.signature" + } + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "enrollmentId": "enrollment-consumer-001", + "status": "ACTIVE", + "programId": "program-flex-demand-response-001", + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "enrolledAt": "2024-10-15T10:35:05Z", + "loggedAt": "2024-10-15T10:35:05Z", + "logReference": "log-enrollment-consumer-001" + } + } + } +} diff --git a/examples/enrollment/v2/on-init-response-conflict.json b/examples/enrollment/v2/on-init-response-conflict.json new file mode 100644 index 00000000..8a3786f8 --- /dev/null +++ b/examples/enrollment/v2/on-init-response-conflict.json @@ -0,0 +1,69 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-conflict-001", + "transaction_id": "txn-onboard-conflict-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-conflict-001", + "beckn:orderStatus": "REJECTED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credentialVerification": { + "status": "VERIFIED" + }, + "conflictCheck": { + "hasConflict": true, + "conflictingEnrollments": [ + { + "enrollmentId": "enrollment-existing-001", + "programId": "program-flex-other-001", + "conflictReason": "Meter umid-001 is already enrolled in program-flex-other-001 from 2024-09-01 to 2025-09-01", + "conflictType": "METER_ALREADY_ENROLLED" + } + ], + "checkedAt": "2024-10-15T10:30:05Z" + } + } + } + }, + "error": { + "code": "BIZ_ENROLLMENT_CONFLICT", + "message": "Enrollment conflicts with existing enrollment. Meter umid-001 is already enrolled in another program.", + "details": { + "path": "$.message.order.orderAttributes.conflictCheck", + "conflictingEnrollmentId": "enrollment-existing-001", + "conflictEndDate": "2025-09-01T00:00:00Z" + } + } +} diff --git a/examples/enrollment/v2/on-init-response-error.json b/examples/enrollment/v2/on-init-response-error.json new file mode 100644 index 00000000..d448eaa6 --- /dev/null +++ b/examples/enrollment/v2/on-init-response-error.json @@ -0,0 +1,50 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-error-001", + "transaction_id": "txn-onboard-error-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-error-001", + "beckn:orderStatus": "REJECTED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + } + } + }, + "error": { + "code": "SEC_CREDENTIAL_VERIFICATION_FAILED", + "message": "Meter ownership credential could not be verified", + "details": { + "path": "$.message.order.orderAttributes.meterOwnershipCredential", + "credentialId": "vc-meter-ownership-001", + "reason": "Invalid signature or expired credential" + } + } +} diff --git a/examples/enrollment/v2/on-init-response-oauth2.json b/examples/enrollment/v2/on-init-response-oauth2.json new file mode 100644 index 00000000..31d3af0a --- /dev/null +++ b/examples/enrollment/v2/on-init-response-oauth2.json @@ -0,0 +1,83 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-oauth2-001", + "transaction_id": "txn-onboard-oauth2-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-oauth2-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OIDC", + "verified": true, + "verifiedAt": "2024-10-15T10:30:05Z", + "subject": "user-12345", + "issuer": "https://utility-idp.example.com", + "scope": "openid profile email meter:read", + "expiresAt": "2024-10-15T11:30:00Z", + "message": "Token verified successfully" + }, + "meters": [ + { + "meterId": "umid-001", + "meterNumber": "MTR-987654321", + "sanctionedLoad": 5.0, + "connectionType": "residential", + "utilityId": "utility-example-001" + }, + { + "meterId": "umid-002", + "meterNumber": "MTR-987654322", + "sanctionedLoad": 10.0, + "connectionType": "commercial", + "utilityId": "utility-example-001" + } + ], + "requiredConsents": [ + { + "type": "DATA_COLLECTION", + "description": "Consent to collect and share meter data for program participation", + "required": true + }, + { + "type": "DER_CONTROL", + "description": "Consent to control DER devices for demand response (if applicable)", + "required": false + } + ] + } + } + } +} diff --git a/examples/enrollment/v2/on-init-response-otp.json b/examples/enrollment/v2/on-init-response-otp.json new file mode 100644 index 00000000..d448515a --- /dev/null +++ b/examples/enrollment/v2/on-init-response-otp.json @@ -0,0 +1,52 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-otp-001", + "transaction_id": "txn-onboard-otp-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-otp-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "pending-verification" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-p2p-trading-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "userAuth": { + "authMethod": "OTP", + "nguid": "LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm", + "message": "OTP sent to +91XXXXXX9999. Valid for 5 minutes.", + "expiresAt": "2024-10-15T10:35:00Z", + "utilityCustomerId": "CUST-123456" + } + } + } + } +} diff --git a/examples/enrollment/v2/on-init-response-success.json b/examples/enrollment/v2/on-init-response-success.json new file mode 100644 index 00000000..d2a5dc34 --- /dev/null +++ b/examples/enrollment/v2/on-init-response-success.json @@ -0,0 +1,94 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-10-15T10:30:05Z", + "message_id": "msg-on-init-consumer-001", + "transaction_id": "txn-onboard-consumer-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "PENDING", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "PENDING" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credentialVerification": { + "status": "VERIFIED", + "verifiedCredentials": [ + { + "credentialId": "vc-meter-ownership-001", + "status": "VERIFIED", + "verifiedAt": "2024-10-15T10:30:05Z" + }, + { + "credentialId": "vc-program-eligibility-001", + "status": "VERIFIED", + "verifiedAt": "2024-10-15T10:30:05Z" + } + ] + }, + "conflictCheck": { + "hasConflict": false, + "checkedAt": "2024-10-15T10:30:05Z", + "message": "No conflicts found with existing enrollments" + }, + "requiredCredentials": [ + { + "type": "MeterOwnershipCredential", + "description": "Proof of meter ownership verified through utility OTP verification", + "status": "PROVIDED" + }, + { + "type": "ProgramEligibilityCredential", + "description": "Proof of program eligibility based on meter type and location", + "status": "PROVIDED" + } + ], + "requiredConsents": [ + { + "type": "DATA_COLLECTION", + "description": "Consent to collect and share meter data for program participation", + "required": true + }, + { + "type": "DER_CONTROL", + "description": "Consent to control DER devices for demand response (if applicable)", + "required": false + }, + { + "type": "CROSS_UTILITY_SHARING", + "description": "Consent to share data across utilities (if applicable)", + "required": false + } + ] + } + } + } +} diff --git a/examples/enrollment/v2/on-update-response-consent-revocation.json b/examples/enrollment/v2/on-update-response-consent-revocation.json new file mode 100644 index 00000000..e0281161 --- /dev/null +++ b/examples/enrollment/v2/on-update-response-consent-revocation.json @@ -0,0 +1,56 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T14:30:05Z", + "message_id": "msg-on-update-consent-revoke-001", + "transaction_id": "txn-revoke-consent-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CONFIRMED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "enrollmentId": "enrollment-consumer-001", + "status": "ACTIVE", + "updateType": "CONSENT_REVOCATION", + "consentRevocation": { + "consentCredentialId": "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001", + "status": "REVOKED", + "revokedAt": "2024-11-20T14:30:05Z", + "statusListUrl": "https://vpp-program-owner.example.com/status/consent-list", + "statusListIndex": "94567", + "message": "Consent has been revoked and added to revocation status list. Future verifications will fail." + } + } + } + } +} diff --git a/examples/enrollment/v2/on-update-response-unenrollment.json b/examples/enrollment/v2/on-update-response-unenrollment.json new file mode 100644 index 00000000..0035b944 --- /dev/null +++ b/examples/enrollment/v2/on-update-response-unenrollment.json @@ -0,0 +1,69 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T15:00:05Z", + "message_id": "msg-on-update-unenroll-001", + "transaction_id": "txn-unenroll-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CANCELLED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-onboard-001", + "beckn:mode": "DIGITAL", + "beckn:fulfillmentStatus": "CANCELLED" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "enrollmentId": "enrollment-consumer-001", + "status": "CANCELLED", + "updateType": "UNENROLLMENT", + "unenrollment": { + "enrollmentId": "enrollment-consumer-001", + "status": "CANCELLED", + "cancelledAt": "2024-11-20T15:00:05Z", + "enrollmentCredentialStatus": { + "statusListUrl": "https://vpp-program-owner.example.com/status/enrollment-list", + "statusListIndex": "12345", + "revoked": true + }, + "consentsRevoked": [ + { + "consentCredentialId": "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001", + "statusListUrl": "https://vpp-program-owner.example.com/status/consent-list", + "statusListIndex": "94567", + "revoked": true + } + ], + "message": "Enrollment and all associated consents have been revoked. Enrollment credential and consent credentials have been added to revocation status lists." + }, + "loggedAt": "2024-11-20T15:00:05Z", + "logReference": "log-unenrollment-consumer-001" + } + } + } +} diff --git a/examples/enrollment/v2/update-request-consent-revocation.json b/examples/enrollment/v2/update-request-consent-revocation.json new file mode 100644 index 00000000..9f646dfc --- /dev/null +++ b/examples/enrollment/v2/update-request-consent-revocation.json @@ -0,0 +1,46 @@ +{ + "context": { + "version": "2.0.0", + "action": "update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T14:30:00Z", + "message_id": "msg-update-consent-revoke-001", + "transaction_id": "txn-revoke-consent-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "updateType": "CONSENT_REVOCATION", + "consentRevocation": { + "consentCredentialId": "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001", + "consentType": "DATA_COLLECTION", + "reason": "USER_REQUESTED", + "revokedAt": "2024-11-20T14:30:00Z", + "effectiveDate": "2024-11-20T14:30:00Z" + } + } + } + } +} diff --git a/examples/enrollment/v2/update-request-unenrollment.json b/examples/enrollment/v2/update-request-unenrollment.json new file mode 100644 index 00000000..3dff613c --- /dev/null +++ b/examples/enrollment/v2/update-request-unenrollment.json @@ -0,0 +1,45 @@ +{ + "context": { + "version": "2.0.0", + "action": "update", + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "timestamp": "2024-11-20T15:00:00Z", + "message_id": "msg-update-unenroll-001", + "transaction_id": "txn-unenroll-001", + "bap_id": "utility-portal.example.com", + "bap_uri": "https://utility-portal.example.com/beckn", + "bpp_id": "vpp-program-owner.example.com", + "bpp_uri": "https://vpp-program-owner.example.com/beckn", + "ttl": "PT30S" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-onboard-consumer-001", + "beckn:orderStatus": "CONFIRMED", + "beckn:seller": "vpp-program-flex-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "did:example:user-12345" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "program-flex-demand-response-001" + } + ], + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "updateType": "UNENROLLMENT", + "unenrollment": { + "enrollmentId": "enrollment-consumer-001", + "reason": "USER_REQUESTED", + "effectiveDate": "2024-11-20T15:00:00Z", + "revokeAllConsents": true + } + } + } + } +} diff --git a/examples/v1-EOS/ev_charging/v1-EOS/cancel/cancel-request.json b/examples/ev-charging/v1-EOS/cancel/cancel-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/cancel/cancel-request.json rename to examples/ev-charging/v1-EOS/cancel/cancel-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/cancel/on_cancel-charger_breakdown-request.json b/examples/ev-charging/v1-EOS/cancel/on_cancel-charger_breakdown-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/cancel/on_cancel-charger_breakdown-request.json rename to examples/ev-charging/v1-EOS/cancel/on_cancel-charger_breakdown-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/cancel/on_cancel-request.json b/examples/ev-charging/v1-EOS/cancel/on_cancel-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/cancel/on_cancel-request.json rename to examples/ev-charging/v1-EOS/cancel/on_cancel-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/confirm/confirm-request.json b/examples/ev-charging/v1-EOS/confirm/confirm-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/confirm/confirm-request.json rename to examples/ev-charging/v1-EOS/confirm/confirm-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/confirm/on_confirm-request.json b/examples/ev-charging/v1-EOS/confirm/on_confirm-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/confirm/on_confirm-request.json rename to examples/ev-charging/v1-EOS/confirm/on_confirm-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/init/init-request.json b/examples/ev-charging/v1-EOS/init/init-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/init/init-request.json rename to examples/ev-charging/v1-EOS/init/init-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/init/on_init-request.json b/examples/ev-charging/v1-EOS/init/on_init-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/init/on_init-request.json rename to examples/ev-charging/v1-EOS/init/on_init-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/rating/on_rating-request.json b/examples/ev-charging/v1-EOS/rating/on_rating-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/rating/on_rating-request.json rename to examples/ev-charging/v1-EOS/rating/on_rating-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/rating/rating-request.json b/examples/ev-charging/v1-EOS/rating/rating-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/rating/rating-request.json rename to examples/ev-charging/v1-EOS/rating/rating-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/search/on_search-request.json b/examples/ev-charging/v1-EOS/search/on_search-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/search/on_search-request.json rename to examples/ev-charging/v1-EOS/search/on_search-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/search/search-request.json b/examples/ev-charging/v1-EOS/search/search-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/search/search-request.json rename to examples/ev-charging/v1-EOS/search/search-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/select/on_select-request.json b/examples/ev-charging/v1-EOS/select/on_select-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/select/on_select-request.json rename to examples/ev-charging/v1-EOS/select/on_select-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/select/select-request.json b/examples/ev-charging/v1-EOS/select/select-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/select/select-request.json rename to examples/ev-charging/v1-EOS/select/select-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/status/on_status-request.json b/examples/ev-charging/v1-EOS/status/on_status-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/status/on_status-request.json rename to examples/ev-charging/v1-EOS/status/on_status-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/status/status-request.json b/examples/ev-charging/v1-EOS/status/status-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/status/status-request.json rename to examples/ev-charging/v1-EOS/status/status-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/support/on_support-request.json b/examples/ev-charging/v1-EOS/support/on_support-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/support/on_support-request.json rename to examples/ev-charging/v1-EOS/support/on_support-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/support/support-request.json b/examples/ev-charging/v1-EOS/support/support-request.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/support/support-request.json rename to examples/ev-charging/v1-EOS/support/support-request.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/update/on_update-request-charging-end.json b/examples/ev-charging/v1-EOS/update/on_update-request-charging-end.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/update/on_update-request-charging-end.json rename to examples/ev-charging/v1-EOS/update/on_update-request-charging-end.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/update/on_update-request-charging-start.json b/examples/ev-charging/v1-EOS/update/on_update-request-charging-start.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/update/on_update-request-charging-start.json rename to examples/ev-charging/v1-EOS/update/on_update-request-charging-start.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/update/update-request-charging-end.json b/examples/ev-charging/v1-EOS/update/update-request-charging-end.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/update/update-request-charging-end.json rename to examples/ev-charging/v1-EOS/update/update-request-charging-end.json diff --git a/examples/v1-EOS/ev_charging/v1-EOS/update/update-request-charging-start.json b/examples/ev-charging/v1-EOS/update/update-request-charging-start.json similarity index 100% rename from examples/v1-EOS/ev_charging/v1-EOS/update/update-request-charging-start.json rename to examples/ev-charging/v1-EOS/update/update-request-charging-start.json diff --git a/examples/p2p-trading-interdiscom/v2/cascaded-confirm-request.json b/examples/p2p-trading-interdiscom/v2/cascaded-confirm-request.json new file mode 100644 index 00000000..6acc95d0 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/cascaded-confirm-request.json @@ -0,0 +1,142 @@ +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "timestamp": "2024-10-04T10:25:00Z", + "message_id": "msg-cascaded-confirm-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-cascaded-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 2.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "p2pTrading-bpp.com", + "accountHolderName": "P2P Trading Platform Pvt Ltd", + "accountNumber": "5555666677", + "ifscCode": "SBIN0001234", + "bankName": "State Bank of India", + "vpa": "p2p-trading@upi" + }, + { + "beneficiaryId": "example-transmission-bpp.com", + "accountHolderName": "Transmission Utility Provider Pvt Ltd", + "accountNumber": "8888999900", + "ifscCode": "AXIS0004567", + "bankName": "Axis Bank", + "vpa": "transmission-utility@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/cascaded-init-request.json b/examples/p2p-trading-interdiscom/v2/cascaded-init-request.json new file mode 100644 index 00000000..d5f7f97d --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/cascaded-init-request.json @@ -0,0 +1,134 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "timestamp": "2024-10-04T10:20:00Z", + "message_id": "msg-cascaded-init-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-cascaded-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 2.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "INITIATED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "p2pTrading-bpp.com", + "accountHolderName": "P2P Trading Platform Pvt Ltd", + "accountNumber": "5555666677", + "ifscCode": "SBIN0001234", + "bankName": "State Bank of India", + "vpa": "p2p-trading@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/cascaded-on-confirm-response.json b/examples/p2p-trading-interdiscom/v2/cascaded-on-confirm-response.json new file mode 100644 index 00000000..3ebe1d61 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/cascaded-on-confirm-response.json @@ -0,0 +1,143 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "timestamp": "2024-10-04T10:25:05Z", + "message_id": "msg-cascaded-on-confirm-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-cascaded-utility-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-cascaded-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 2.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "p2pTrading-bpp.com", + "accountHolderName": "P2P Trading Platform Pvt Ltd", + "accountNumber": "5555666677", + "ifscCode": "SBIN0001234", + "bankName": "State Bank of India", + "vpa": "p2p-trading@upi" + }, + { + "beneficiaryId": "example-transmission-bpp.com", + "accountHolderName": "Transmission Utility Provider Pvt Ltd", + "accountNumber": "8888999900", + "ifscCode": "AXIS0004567", + "bankName": "Axis Bank", + "vpa": "transmission-utility@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/cascaded-on-init-response.json b/examples/p2p-trading-interdiscom/v2/cascaded-on-init-response.json new file mode 100644 index 00000000..08e072b3 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/cascaded-on-init-response.json @@ -0,0 +1,142 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "timestamp": "2024-10-04T10:20:05Z", + "message_id": "msg-cascaded-on-init-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-cascaded-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 2.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "p2pTrading-bpp.com", + "accountHolderName": "P2P Trading Platform Pvt Ltd", + "accountNumber": "5555666677", + "ifscCode": "SBIN0001234", + "bankName": "State Bank of India", + "vpa": "p2p-trading@upi" + }, + { + "beneficiaryId": "example-transmission-bpp.com", + "accountHolderName": "Transmission Utility Provider Pvt Ltd", + "accountNumber": "8888999900", + "ifscCode": "AXIS0004567", + "bankName": "Axis Bank", + "vpa": "transmission-utility@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/confirm-request.json b/examples/p2p-trading-interdiscom/v2/confirm-request.json new file mode 100644 index 00000000..bee451f3 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/confirm-request.json @@ -0,0 +1,176 @@ +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "timestamp": "2024-10-04T10:25:00Z", + "message_id": "msg-confirm-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED" + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/confirm-response.json b/examples/p2p-trading-interdiscom/v2/confirm-response.json new file mode 100644 index 00000000..9a150dea --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/confirm-response.json @@ -0,0 +1,177 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "timestamp": "2024-10-04T10:25:05Z", + "message_id": "msg-on-confirm-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED" + } + } + } +} diff --git a/examples/v2/P2P_Trading/discover-request.json b/examples/p2p-trading-interdiscom/v2/discover-request.json similarity index 61% rename from examples/v2/P2P_Trading/discover-request.json rename to examples/p2p-trading-interdiscom/v2/discover-request.json index bea3e96f..790f6a4a 100644 --- a/examples/v2/P2P_Trading/discover-request.json +++ b/examples/p2p-trading-interdiscom/v2/discover-request.json @@ -10,7 +10,7 @@ "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0", "location": { "city": { "code": "BLR", @@ -20,14 +20,15 @@ "code": "IND", "name": "India" } - } + }, + "schema_context": [ + "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld" + ] }, "message": { - "text_search": "solar energy grid injection", "filters": { "type": "jsonpath", - "expression": "$[?(@.itemAttributes.sourceType == 'SOLAR' && @.itemAttributes.deliveryMode == 'GRID_INJECTION' && @.itemAttributes.availableQuantity >= 10.0 && @.itemAttributes.productionWindow.start <= '2024-10-04T10:00:00Z' && @.itemAttributes.productionWindow.end >= '2024-10-04T18:00:00Z')]" + "expression": "$[?('p2p-interdiscom-trading-pilot-network' == @.beckn:networkId && @.beckn:provider.beckn:providerAttributes.utilityId == 'TPDDL-DL')]" } } } - diff --git a/examples/p2p-trading-interdiscom/v2/discover-response.json b/examples/p2p-trading-interdiscom/v2/discover-response.json new file mode 100644 index 00000000..13327659 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/discover-response.json @@ -0,0 +1,141 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_discover", + "timestamp": "2024-10-04T10:00:05Z", + "message_id": "msg-on-discover-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "catalogs": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Catalog", + "beckn:id": "catalog-energy-001", + "beckn:bppId": "bpp.energy-provider.com", + "beckn:bppUri": "https://bpp.energy-provider.com", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Trading Catalog" + }, + "beckn:items": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-interdiscom-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 30.5 kWh" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + }, + "beckn:providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200300", + "utilityId": "TPDDL-DL", + "utilityCustomerId": "TPDDL-CUST-001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "meterId": "der://meter/100200300" + } + } + ], + "beckn:offers": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer - 6am-12pm" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer - 12pm-6pm" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + ] + } + ] + } +} diff --git a/examples/p2p-trading-interdiscom/v2/init-request.json b/examples/p2p-trading-interdiscom/v2/init-request.json new file mode 100644 index 00000000..990c4b8d --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/init-request.json @@ -0,0 +1,190 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "timestamp": "2024-10-04T10:20:00Z", + "message_id": "msg-init-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "INITIATED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "bap.energy-consumer.com", + "accountHolderName": "Energy Consumer BAP Pvt Ltd", + "accountNumber": "1234567890", + "ifscCode": "HDFC0001234", + "bankName": "HDFC Bank", + "vpa": "energy-consumer@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/init-response.json b/examples/p2p-trading-interdiscom/v2/init-response.json new file mode 100644 index 00000000..f8942f3a --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/init-response.json @@ -0,0 +1,223 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "timestamp": "2024-10-04T10:20:05Z", + "message_id": "msg-on-init-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:acceptedPaymentMethod": ["UPI", "BANK_TRANSFER", "WALLET"], + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "bap.energy-consumer.com", + "accountHolderName": "Energy Consumer BAP Pvt Ltd", + "accountNumber": "1234567890", + "ifscCode": "HDFC0001234", + "bankName": "HDFC Bank", + "vpa": "energy-consumer@upi" + }, + { + "beneficiaryId": "bpp.energy-provider.com", + "accountHolderName": "Solar Farm Energy Provider Pvt Ltd", + "accountNumber": "9876543210", + "ifscCode": "ICICI0005678", + "bankName": "ICICI Bank", + "vpa": "solar-provider@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/on-update-response-curtailment.json b/examples/p2p-trading-interdiscom/v2/on-update-response-curtailment.json new file mode 100644 index 00000000..be5ae5b2 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/on-update-response-curtailment.json @@ -0,0 +1,152 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T14:30:00Z", + "message_id": "msg-on-update-curtailment-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "INPROGRESS", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 8.5, + "curtailedQuantity": 6.5, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 8.5, + "allocatedEnergy": 8.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 1.36, + "components": [ + { + "type": "UNIT", + "value": 1.28, + "currency": "USD", + "description": "Energy value for delivered quantity (8.5 kWh × $0.15)" + }, + { + "type": "FEE", + "value": 0.03, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.04, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 1.36 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "ADJUSTED" + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/on-update-response-final-invoice.json b/examples/p2p-trading-interdiscom/v2/on-update-response-final-invoice.json new file mode 100644 index 00000000..9c603f9e --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/on-update-response-final-invoice.json @@ -0,0 +1,243 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T18:15:00Z", + "message_id": "msg-on-update-final-invoice-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "INPROGRESS", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 15.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 15.0, + "allocatedEnergy": 15.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T18:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T12:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 10.0, + "allocatedEnergy": 10.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T18:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED", + "beckn:acceptedPaymentMethod": ["UPI", "BANK_TRANSFER"], + "beckn:paymentURL": "https://payments.seller-platform.com/track?txn=TXN-ENERGY-001", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "bpp.energy-provider.com", + "accountHolderName": "Solar Farm Energy Provider Pvt Ltd", + "accountNumber": "9876543210", + "ifscCode": "ICICI0005678", + "bankName": "ICICI Bank", + "vpa": "solar-provider@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/on-update-response-settlement-complete.json b/examples/p2p-trading-interdiscom/v2/on-update-response-settlement-complete.json new file mode 100644 index 00000000..da6ade7c --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/on-update-response-settlement-complete.json @@ -0,0 +1,111 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T18:45:00Z", + "message_id": "msg-on-update-settlement-complete-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "COMPLETED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": ["energy-resource-solar-001"] + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": ["energy-resource-solar-001"] + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "SETTLED", + "beckn:paidAt": "2024-10-04T18:40:00Z", + "beckn:txnRef": "TXN-ENERGY-001-SETTLED" + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/publish-catalog.json b/examples/p2p-trading-interdiscom/v2/publish-catalog.json new file mode 100644 index 00000000..b73e0e57 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/publish-catalog.json @@ -0,0 +1,176 @@ +{ + "context": { + "version": "2.0.0", + "action": "catalog_publish", + "timestamp": "2024-10-04T08:00:00Z", + "message_id": "msg-publish-001", + "transaction_id": "txn-catalog-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "catalogs": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Catalog", + "beckn:id": "catalog-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Trading Catalog" + }, + "beckn:bppId": "bpp.energy-provider.com", + "beckn:bppUri": "https://bpp.energy-provider.com", + "beckn:items": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-interdiscom-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 30.5 kWh", + "beckn:shortDesc": "Carbon Offset Certified Solar Energy", + "beckn:longDesc": "High-quality solar energy from verified source with carbon offset certification" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + }, + "beckn:providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200300", + "utilityId": "TPDDL-DL", + "utilityCustomerId": "TPDDL-CUST-001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "meterId": "der://meter/100200300" + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-interdiscom-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 50.0 kWh", + "beckn:shortDesc": "Standard Solar Energy", + "beckn:longDesc": "Reliable solar energy from verified source" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + }, + "beckn:providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200301", + "utilityId": "TPDDL-DL", + "utilityCustomerId": "TPDDL-CUST-001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "meterId": "der://meter/100200301" + } + } + ], + "beckn:offers": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Offer - Morning Slot" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 30.5, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T10:00:00Z", + "schema:endTime": "2024-10-04T14:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + } + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Offer - Afternoon Slot" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-002" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.12, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 50.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T14:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-04T13:00:00Z" + } + } + } + ] + } + ] + } +} diff --git a/examples/p2p-trading-interdiscom/v2/publish-reduce-catalog-inventory.json b/examples/p2p-trading-interdiscom/v2/publish-reduce-catalog-inventory.json new file mode 100644 index 00000000..05fc153d --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/publish-reduce-catalog-inventory.json @@ -0,0 +1,177 @@ +{ + "context": { + "version": "2.0.0", + "action": "catalog_publish", + "timestamp": "2024-10-04T08:00:00Z", + "message_id": "msg-publish-001", + "transaction_id": "txn-catalog-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "catalogs": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Catalog", + "beckn:id": "catalog-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Trading Catalog" + }, + "beckn:bppId": "bpp.energy-provider.com", + "beckn:bppUri": "https://bpp.energy-provider.com", + "beckn:isActive": true, + "beckn:items": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-interdiscom-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 3.5 kWh", + "beckn:shortDesc": "Carbon Offset Certified Solar Energy", + "beckn:longDesc": "High-quality solar energy from verified source with carbon offset certification" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + }, + "beckn:providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200300", + "utilityId": "TPDDL-DL", + "utilityCustomerId": "TPDDL-CUST-001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "meterId": "der://meter/100200300" + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-interdiscom-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 50.0 kWh", + "beckn:shortDesc": "Standard Solar Energy", + "beckn:longDesc": "Reliable solar energy from verified source" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + }, + "beckn:providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200301", + "utilityId": "TPDDL-DL", + "utilityCustomerId": "TPDDL-CUST-001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "meterId": "der://meter/100200301" + } + } + ], + "beckn:offers": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Daily Settlement Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.5, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T10:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-04T23:59:59Z" + } + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Bulk Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-002" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.12, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T08:00:00Z", + "schema:endTime": "2024-10-04T16:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-11T23:59:59Z" + } + } + } + ] + } + ] + } +} diff --git a/examples/p2p-trading-interdiscom/v2/publish-revoke-catalog.json b/examples/p2p-trading-interdiscom/v2/publish-revoke-catalog.json new file mode 100644 index 00000000..6aa4156a --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/publish-revoke-catalog.json @@ -0,0 +1,175 @@ +{ + "context": { + "version": "2.0.0", + "action": "catalog_publish", + "timestamp": "2024-10-04T08:00:00Z", + "message_id": "msg-publish-001", + "transaction_id": "txn-catalog-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "catalogs": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Catalog", + "beckn:id": "catalog-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Trading Catalog" + }, + "beckn:bppId": "bpp.energy-provider.com", + "beckn:bppUri": "https://bpp.energy-provider.com", + "beckn:isActive": false, + "beckn:items": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-interdiscom-trading-pilot-network"], + "beckn:id": "energy-resource-solar-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 30.5 kWh", + "beckn:shortDesc": "Carbon Offset Certified Solar Energy", + "beckn:longDesc": "High-quality solar energy from verified source with carbon offset certification" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + }, + "beckn:providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200300", + "utilityId": "TPDDL-DL", + "utilityCustomerId": "TPDDL-CUST-001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "meterId": "der://meter/100200300" + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-interdiscom-trading-pilot-network"], + "beckn:id": "energy-resource-solar-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 50.0 kWh", + "beckn:shortDesc": "Standard Solar Energy", + "beckn:longDesc": "Reliable solar energy from verified source" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + }, + "beckn:providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200301", + "utilityId": "TPDDL-DL", + "utilityCustomerId": "TPDDL-CUST-001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "meterId": "der://meter/100200301" + } + } + ], + "beckn:offers": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Daily Settlement Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 30.5, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T10:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-04T23:59:59Z" + } + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Bulk Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-002" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.12, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 50.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T08:00:00Z", + "schema:endTime": "2024-10-04T16:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-11T23:59:59Z" + } + } + } + ] + } + ] + } +} diff --git a/examples/p2p-trading-interdiscom/v2/select-request.json b/examples/p2p-trading-interdiscom/v2/select-request.json new file mode 100644 index 00000000..064c3733 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/select-request.json @@ -0,0 +1,159 @@ +{ + "context": { + "version": "2.0.0", + "action": "select", + "timestamp": "2024-10-04T10:15:00Z", + "message_id": "msg-select-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/select-response.json b/examples/p2p-trading-interdiscom/v2/select-response.json new file mode 100644 index 00000000..52b36c6a --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/select-response.json @@ -0,0 +1,189 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_select", + "timestamp": "2024-10-04T10:15:05Z", + "message_id": "msg-on-select-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:paymentStatus": "PENDING", + "beckn:acceptedPaymentMethod": ["UPI", "BANK_TRANSFER", "WALLET"] + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/v2/P2P_Trading/status-request.json b/examples/p2p-trading-interdiscom/v2/status-request.json similarity index 70% rename from examples/v2/P2P_Trading/status-request.json rename to examples/p2p-trading-interdiscom/v2/status-request.json index 54efa276..a332a450 100644 --- a/examples/v2/P2P_Trading/status-request.json +++ b/examples/p2p-trading-interdiscom/v2/status-request.json @@ -10,14 +10,11 @@ "bpp_id": "bpp.energy-provider.com", "bpp_uri": "https://bpp.energy-provider.com", "ttl": "PT30S", - "domain": "energy-trade" + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" }, "message": { "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", "beckn:id": "order-energy-001" } } } - diff --git a/examples/p2p-trading-interdiscom/v2/status-response-completed.json b/examples/p2p-trading-interdiscom/v2/status-response-completed.json new file mode 100644 index 00000000..d38b6e06 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/status-response-completed.json @@ -0,0 +1,250 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T18:30:00Z", + "message_id": "msg-on-status-completed-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "COMPLETED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 15.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + }, + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T09:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T12:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T12:00:00Z", + "schema:endTime": "2024-10-04T15:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 5.0, + "allocatedEnergy": 5.0, + "unit": "kWh" + }, + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T15:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 5.0, + "allocatedEnergy": 5.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T18:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:orderValue": { + "currency": "USD", + "value": 4.25, + "components": [ + { + "type": "UNIT", + "value": 4.05, + "currency": "USD", + "description": "Energy value (15 kWh × $0.15 + 10 kWh × $0.18)" + }, + { + "type": "FEE", + "value": 0.08, + "currency": "USD", + "description": "Buyer platform fee (2%)" + }, + { + "type": "FEE", + "value": 0.12, + "currency": "USD", + "description": "Seller platform fee (3%)" + } + ] + }, + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "SETTLED", + "beckn:paidAt": "2024-10-04T19:00:00Z" + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/status-response-curtailed.json b/examples/p2p-trading-interdiscom/v2/status-response-curtailed.json new file mode 100644 index 00000000..4ade6145 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/status-response-curtailed.json @@ -0,0 +1,217 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T16:00:00Z", + "message_id": "msg-on-status-curtailed-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "PARTIALLYFULFILLED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "curtailedQuantity": 5.0, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T14:30:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 10.0, + "allocatedEnergy": 10.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "FAILED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 0.0, + "curtailedQuantity": 10.0, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 1.50 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "COMPLETED", + "beckn:paymentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld", + "@type": "PaymentSettlement", + "settlementAccounts": [ + { + "beneficiaryId": "bap.energy-consumer.com", + "accountHolderName": "Energy Consumer BAP Pvt Ltd", + "accountNumber": "1234567890", + "ifscCode": "HDFC0001234", + "bankName": "HDFC Bank", + "vpa": "energy-consumer@upi" + }, + { + "beneficiaryId": "bpp.energy-provider.com", + "accountHolderName": "Solar Farm Energy Provider Pvt Ltd", + "accountNumber": "9876543210", + "ifscCode": "ICICI0005678", + "bankName": "ICICI Bank", + "vpa": "solar-provider@upi" + } + ] + } + } + } + } +} diff --git a/examples/p2p-trading-interdiscom/v2/status-response.json b/examples/p2p-trading-interdiscom/v2/status-response.json new file mode 100644 index 00000000..e2305ec9 --- /dev/null +++ b/examples/p2p-trading-interdiscom/v2/status-response.json @@ -0,0 +1,191 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T15:00:05Z", + "message_id": "msg-on-status-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 7.5, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T15:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "PENDING", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 0.0, + "meterReadings": [], + "lastUpdated": "2024-10-04T15:00:00Z" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.18, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T11:00:00Z" + } + } + } + } + ], + "beckn:payment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Payment", + "beckn:id": "payment-p2p-energy-001", + "beckn:amount": { + "currency": "USD", + "value": 4.25 + }, + "beckn:beneficiary": "BPP", + "beckn:paymentStatus": "AUTHORIZED" + } + } + } +} diff --git a/examples/p2p-trading/v2/cascaded-confirm-request.json b/examples/p2p-trading/v2/cascaded-confirm-request.json new file mode 100644 index 00000000..98f9106e --- /dev/null +++ b/examples/p2p-trading/v2/cascaded-confirm-request.json @@ -0,0 +1,102 @@ +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "timestamp": "2024-10-04T10:25:00Z", + "message_id": "msg-cascaded-confirm-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": 15.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/cascaded-init-request.json b/examples/p2p-trading/v2/cascaded-init-request.json new file mode 100644 index 00000000..ed3bdff5 --- /dev/null +++ b/examples/p2p-trading/v2/cascaded-init-request.json @@ -0,0 +1,102 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "timestamp": "2024-10-04T10:20:00Z", + "message_id": "msg-cascaded-init-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": 15.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/cascaded-on-confirm-response.json b/examples/p2p-trading/v2/cascaded-on-confirm-response.json new file mode 100644 index 00000000..20a4f110 --- /dev/null +++ b/examples/p2p-trading/v2/cascaded-on-confirm-response.json @@ -0,0 +1,103 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "timestamp": "2024-10-04T10:25:05Z", + "message_id": "msg-cascaded-on-confirm-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-cascaded-utility-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": 15.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/cascaded-on-init-response.json b/examples/p2p-trading/v2/cascaded-on-init-response.json new file mode 100644 index 00000000..e940a63e --- /dev/null +++ b/examples/p2p-trading/v2/cascaded-on-init-response.json @@ -0,0 +1,102 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "timestamp": "2024-10-04T10:20:05Z", + "message_id": "msg-cascaded-on-init-001", + "transaction_id": "txn-cascaded-energy-001", + "bap_id": "p2pTrading-bpp.com", + "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", + "bpp_id": "example-transmission-bpp.com", + "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "p2pTrading-bpp.com", + "bpp_id": "example-transmission-bpp.com", + "total_quantity": 15.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/confirm-request.json b/examples/p2p-trading/v2/confirm-request.json new file mode 100644 index 00000000..a4216c56 --- /dev/null +++ b/examples/p2p-trading/v2/confirm-request.json @@ -0,0 +1,161 @@ +{ + "context": { + "version": "2.0.0", + "action": "confirm", + "timestamp": "2024-10-04T10:25:00Z", + "message_id": "msg-confirm-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/confirm-response.json b/examples/p2p-trading/v2/confirm-response.json new file mode 100644 index 00000000..ff98f4a3 --- /dev/null +++ b/examples/p2p-trading/v2/confirm-response.json @@ -0,0 +1,162 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "timestamp": "2024-10-04T10:25:05Z", + "message_id": "msg-on-confirm-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/discover-request.json b/examples/p2p-trading/v2/discover-request.json new file mode 100644 index 00000000..ba5a76fe --- /dev/null +++ b/examples/p2p-trading/v2/discover-request.json @@ -0,0 +1,34 @@ +{ + "context": { + "version": "2.0.0", + "action": "discover", + "timestamp": "2024-10-04T10:00:00Z", + "message_id": "msg-discover-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0", + "location": { + "city": { + "code": "BLR", + "name": "Bangalore" + }, + "country": { + "code": "IND", + "name": "India" + } + }, + "schema_context": [ + "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld" + ] + }, + "message": { + "filters": { + "type": "jsonpath", + "expression": "$[?('p2p-trading-pilot-network' == @.beckn:networkId && @.beckn:itemAttributes.sourceType == 'SOLAR' && @.beckn:itemAttributes.deliveryMode == 'GRID_INJECTION' && @.beckn:itemAttributes.availableQuantity >= 10.0 )]" + } + } +} diff --git a/examples/p2p-trading/v2/discover-response.json b/examples/p2p-trading/v2/discover-response.json new file mode 100644 index 00000000..91cbe745 --- /dev/null +++ b/examples/p2p-trading/v2/discover-response.json @@ -0,0 +1,170 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_discover", + "timestamp": "2024-10-04T10:00:05Z", + "message_id": "msg-on-discover-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "catalogs": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Catalog", + "beckn:id": "catalog-energy-001", + "beckn:bppId": "bpp.energy-provider.com", + "beckn:bppUri": "https://bpp.energy-provider.com", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Trading Catalog" + }, + "beckn:items": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 30.5 kWh" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "deliveryMode": "GRID_INJECTION", + "certificationStatus": "Carbon Offset Certified", + "meterId": "der://meter/100200300", + "availableQuantity": 30.5, + "productionWindow": [ + { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T10:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + ], + "sourceVerification": { + "verified": true, + "verificationDate": "2024-09-01T00:00:00Z", + "certificates": [ + "https://example.com/certs/solar-panel-cert.pdf" + ] + }, + "productionAsynchronous": true + } + } + ], + "beckn:offers": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer - 6am-12pm" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "wheelingCharges": { + "amount": 2.5, + "currency": "USD", + "description": "PG&E Grid Services wheeling charge" + }, + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T23:59:59Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-afternoon-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer - 12pm-6pm" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "wheelingCharges": { + "amount": 2.5, + "currency": "USD", + "description": "PG&E Grid Services wheeling charge" + }, + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T23:59:59Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + ] + } + ] + } +} diff --git a/examples/p2p-trading/v2/init-request.json b/examples/p2p-trading/v2/init-request.json new file mode 100644 index 00000000..33f2233b --- /dev/null +++ b/examples/p2p-trading/v2/init-request.json @@ -0,0 +1,161 @@ +{ + "context": { + "version": "2.0.0", + "action": "init", + "timestamp": "2024-10-04T10:20:00Z", + "message_id": "msg-init-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/init-response.json b/examples/p2p-trading/v2/init-response.json new file mode 100644 index 00000000..c6e9dede --- /dev/null +++ b/examples/p2p-trading/v2/init-response.json @@ -0,0 +1,161 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_init", + "timestamp": "2024-10-04T10:20:05Z", + "message_id": "msg-on-init-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ], + "beckn:fulfillment": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Fulfillment", + "beckn:id": "fulfillment-energy-001", + "beckn:mode": "DELIVERY" + } + } + } +} diff --git a/examples/p2p-trading/v2/on-update-response-curtailment.json b/examples/p2p-trading/v2/on-update-response-curtailment.json new file mode 100644 index 00000000..fb79a3b1 --- /dev/null +++ b/examples/p2p-trading/v2/on-update-response-curtailment.json @@ -0,0 +1,113 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_update", + "timestamp": "2024-10-04T14:30:00Z", + "message_id": "msg-on-update-curtailment-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "INPROGRESS", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 8.5, + "curtailedQuantity": 6.5, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 8.5, + "allocatedEnergy": 8.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/p2p-trading/v2/publish-catalog.json b/examples/p2p-trading/v2/publish-catalog.json new file mode 100644 index 00000000..ddc17495 --- /dev/null +++ b/examples/p2p-trading/v2/publish-catalog.json @@ -0,0 +1,206 @@ +{ + "context": { + "version": "2.0.0", + "action": "catalog_publish", + "timestamp": "2024-10-04T08:00:00Z", + "message_id": "msg-publish-001", + "transaction_id": "txn-catalog-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "catalogs": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Catalog", + "beckn:id": "catalog-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy Trading Catalog" + }, + "beckn:bppId": "bpp.energy-provider.com", + "beckn:bppUri": "https://bpp.energy-provider.com", + "beckn:items": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 30.5 kWh", + "beckn:shortDesc": "Carbon Offset Certified Solar Energy", + "beckn:longDesc": "High-quality solar energy from verified source with carbon offset certification" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "deliveryMode": "GRID_INJECTION", + "certificationStatus": "Carbon Offset Certified", + "meterId": "der://meter/100200300", + "availableQuantity": 30.5, + "productionWindow": [ + { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T10:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + } + ], + "sourceVerification": { + "verified": true, + "verificationDate": "2024-09-01T00:00:00Z", + "certificates": [ + "https://example.com/certs/solar-panel-cert.pdf" + ] + }, + "productionAsynchronous": true + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Item", + "beckn:networkId": ["p2p-trading-pilot-network"], + "beckn:isActive": true, + "beckn:id": "energy-resource-solar-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Energy - 50.0 kWh", + "beckn:shortDesc": "Standard Solar Energy", + "beckn:longDesc": "Reliable solar energy from verified source" + }, + "beckn:provider": { + "beckn:id": "provider-solar-farm-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Solar Farm 001" + } + }, + "beckn:itemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld", + "@type": "EnergyResource", + "sourceType": "SOLAR", + "deliveryMode": "GRID_INJECTION", + "certificationStatus": "Standard Certified", + "meterId": "der://meter/100200301", + "availableQuantity": 50.0, + "productionWindow": [ + { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T08:00:00Z", + "schema:endTime": "2024-10-04T16:00:00Z" + } + ], + "sourceVerification": { + "verified": true, + "verificationDate": "2024-09-01T00:00:00Z", + "certificates": [ + "https://example.com/certs/solar-panel-cert-2.pdf" + ] + }, + "productionAsynchronous": true + } + } + ], + "beckn:offers": [ + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Daily Settlement Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "schema:unitText": "kWh" + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "wheelingCharges": { + "amount": 2.5, + "currency": "USD", + "description": "PG&E Grid Services wheeling charge" + }, + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-04T23:59:59Z" + }, + "beckn:maxQuantity": { + "unitQuantity": 30.5, + "unitText": "kWh", + "unitCode": "KWH" + } + } + }, + { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-energy-002", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Bulk Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-002" + ], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.12, + "schema:priceCurrency": "USD", + "schema:unitText": "kWh" + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "WEEKLY", + "wheelingCharges": { + "amount": 2.0, + "currency": "USD", + "description": "PG&E Grid Services wheeling charge" + }, + "minimumQuantity": 10.0, + "maximumQuantity": 500.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T00:00:00Z", + "schema:endTime": "2024-10-11T23:59:59Z" + }, + "beckn:maxQuantity": { + "unitQuantity": 50.0, + "unitText": "kWh", + "unitCode": "KWH" + } + } + } + ] + } + ] + } +} diff --git a/examples/p2p-trading/v2/select-request.json b/examples/p2p-trading/v2/select-request.json new file mode 100644 index 00000000..8fb30ef8 --- /dev/null +++ b/examples/p2p-trading/v2/select-request.json @@ -0,0 +1,155 @@ +{ + "context": { + "version": "2.0.0", + "action": "select", + "timestamp": "2024-10-04T10:15:00Z", + "message_id": "msg-select-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/p2p-trading/v2/select-response.json b/examples/p2p-trading/v2/select-response.json new file mode 100644 index 00000000..1e4ef5de --- /dev/null +++ b/examples/p2p-trading/v2/select-response.json @@ -0,0 +1,155 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_select", + "timestamp": "2024-10-04T10:15:05Z", + "message_id": "msg-on-select-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": 25.0 + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + } + }, + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/p2p-trading/v2/status-request.json b/examples/p2p-trading/v2/status-request.json new file mode 100644 index 00000000..510c483d --- /dev/null +++ b/examples/p2p-trading/v2/status-request.json @@ -0,0 +1,20 @@ +{ + "context": { + "version": "2.0.0", + "action": "status", + "timestamp": "2024-10-04T15:00:00Z", + "message_id": "msg-status-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "beckn:id": "order-energy-001" + } + } +} \ No newline at end of file diff --git a/examples/p2p-trading/v2/status-response-completed.json b/examples/p2p-trading/v2/status-response-completed.json new file mode 100644 index 00000000..6b446f3a --- /dev/null +++ b/examples/p2p-trading/v2/status-response-completed.json @@ -0,0 +1,213 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T18:30:00Z", + "message_id": "msg-on-status-completed-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "COMPLETED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 15.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + }, + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T09:00:00Z", + "schema:endTime": "2024-10-04T12:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T12:00:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T12:00:00Z", + "schema:endTime": "2024-10-04T15:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 5.0, + "allocatedEnergy": 5.0, + "unit": "kWh" + }, + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T15:00:00Z", + "schema:endTime": "2024-10-04T18:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 5.0, + "allocatedEnergy": 5.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T18:00:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/p2p-trading/v2/status-response-curtailed.json b/examples/p2p-trading/v2/status-response-curtailed.json new file mode 100644 index 00000000..c4d1b4f9 --- /dev/null +++ b/examples/p2p-trading/v2/status-response-curtailed.json @@ -0,0 +1,183 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T16:00:00Z", + "message_id": "msg-on-status-curtailed-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "PARTIALLYFULFILLED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "COMPLETED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 10.0, + "curtailedQuantity": 5.0, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T14:30:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 10.0, + "allocatedEnergy": 10.0, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "FAILED", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 0.0, + "curtailedQuantity": 10.0, + "curtailmentReason": "GRID_OUTAGE", + "meterReadings": [], + "lastUpdated": "2024-10-04T14:30:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/p2p-trading/v2/status-response.json b/examples/p2p-trading/v2/status-response.json new file mode 100644 index 00000000..8cf4e314 --- /dev/null +++ b/examples/p2p-trading/v2/status-response.json @@ -0,0 +1,179 @@ +{ + "context": { + "version": "2.0.0", + "action": "on_status", + "timestamp": "2024-10-04T15:00:05Z", + "message_id": "msg-on-status-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer" + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "IN_PROGRESS", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 7.5, + "meterReadings": [ + { + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2024-10-04T06:00:00Z", + "schema:endTime": "2024-10-04T09:00:00Z" + }, + "consumedEnergy": 0.0, + "producedEnergy": 7.5, + "allocatedEnergy": 7.5, + "unit": "kWh" + } + ], + "lastUpdated": "2024-10-04T15:00:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-morning-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.15, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + } + } + } + }, + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 10.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "UTIL-CUST-123456" + }, + "fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld", + "@type": "EnergyTradeDelivery", + "deliveryStatus": "PENDING", + "deliveryMode": "GRID_INJECTION", + "deliveredQuantity": 0.0, + "meterReadings": [], + "lastUpdated": "2024-10-04T15:00:00Z" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-afternoon-001", + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Afternoon Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": [ + "energy-resource-solar-001" + ], + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "settlementType": "DAILY", + "sourceMeterId": "der://meter/100200300", + "minimumQuantity": 1.0, + "maximumQuantity": 100.0, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + }, + "beckn:price": { + "value": 0.18, + "currency": "USD", + "unitText": "kWh" + }, + "beckn:maxQuantity": { + "unitQuantity": 15.0, + "unitText": "kWh", + "unitCode": "KWH" + }, + "beckn:timeWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T12:00:00Z", + "schema:endTime": "2026-01-09T18:00:00Z" + } + } + } + } + ] + } + } +} diff --git a/examples/v2/P2P_Trading/cascaded-init-request.json b/examples/v2/P2P_Trading/cascaded-init-request.json deleted file mode 100644 index 4fec5359..00000000 --- a/examples/v2/P2P_Trading/cascaded-init-request.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "init", - "timestamp": "2024-10-04T10:20:00Z", - "message_id": "msg-cascaded-init-001", - "transaction_id": "txn-cascaded-energy-001", - "bap_id": "p2pTrading-bpp.com", - "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", - "bpp_id": "example-transmission-bpp.com", - "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", - "ttl": "PT30S", - "domain": "energy-trade", - "location": { - "city": { - "code": "std:522", - "name": "Lucknow" - }, - "country": { - "code": "IND", - "name": "India" - } - } - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-cascaded-utility-001", - "beckn:provider": { - "@type": "beckn:Provider", - "beckn:id": "provider-uppcl-001", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "UPPCL" - } - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-utility-registration-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:customer": { - "@type": "beckn:Customer", - "beckn:person": { - "@type": "schema:Person", - "schema:name": "Raj" - }, - "beckn:contact": { - "@type": "schema:ContactPoint", - "schema:telephone": "+91-1276522222" - } - }, - "beckn:stops": [ - { - "@type": "beckn:Stop", - "beckn:id": "stop-source-utility-001", - "beckn:type": "START", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "92982739" - }, - "beckn:time": { - "@type": "beckn:Time", - "beckn:range": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - } - } - }, - { - "@type": "beckn:Stop", - "beckn:id": "stop-target-utility-001", - "beckn:type": "END", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "98765456" - }, - "beckn:time": { - "@type": "beckn:Time", - "beckn:range": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - } - } - } - ] - } - ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "PENDING", - "sourceMeterId": "92982739", - "targetMeterId": "98765456", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR" - }, - "beckn:billing": { - "@type": "beckn:Billing", - "beckn:name": "p2p-Trading-BPP", - "beckn:email": "p2tbpp@example.com", - "beckn:phone": "+91-1276522222" - } - } - } -} diff --git a/examples/v2/P2P_Trading/cascaded-on-init-response.json b/examples/v2/P2P_Trading/cascaded-on-init-response.json deleted file mode 100644 index 16f4030e..00000000 --- a/examples/v2/P2P_Trading/cascaded-on-init-response.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "on_init", - "timestamp": "2024-10-04T10:20:05Z", - "message_id": "msg-cascaded-on-init-001", - "transaction_id": "txn-cascaded-energy-001", - "bap_id": "p2pTrading-bpp.com", - "bap_uri": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2", - "bpp_id": "example-transmission-bpp.com", - "bpp_uri": "https://api.example-transmission-bpp.com/pilot/bpp/", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-cascaded-utility-001", - "beckn:provider": { - "@type": "beckn:Provider", - "beckn:id": "provider-uppcl-001", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "UPPCL" - } - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-utility-registration-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:customer": { - "@type": "beckn:Customer", - "beckn:person": { - "@type": "schema:Person", - "schema:name": "Raj" - }, - "beckn:contact": { - "@type": "schema:ContactPoint", - "schema:telephone": "+91-1276522222" - } - }, - "beckn:stops": [ - { - "@type": "beckn:Stop", - "beckn:id": "stop-source-utility-001", - "beckn:type": "START", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "92982739" - } - }, - { - "@type": "beckn:Stop", - "beckn:id": "stop-target-utility-001", - "beckn:type": "END", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "98765456" - } - } - ] - } - ], - "beckn:quote": { - "@type": "beckn:Quotation", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 2.5, - "schema:priceCurrency": "INR" - }, - "beckn:breakup": [ - { - "@type": "beckn:Breakup", - "beckn:title": "Wheeling Charge", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 2.5, - "schema:priceCurrency": "INR" - } - } - ] - }, - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "PENDING", - "sourceMeterId": "92982739", - "targetMeterId": "98765456", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR" - }, - "beckn:billing": { - "@type": "beckn:Billing", - "beckn:name": "p2p-Trading-BPP", - "beckn:email": "p2ptbpp@example.com", - "beckn:phone": "+91-1276522222" - }, - "beckn:cancellationTerms": [ - { - "@type": "beckn:CancellationTerm", - "beckn:externalRef": { - "@type": "schema:MediaObject", - "schema:encodingFormat": "text/html", - "schema:contentUrl": "https://mvvnl.in/cancellation_terms.html" - } - } - ] - } - } -} diff --git a/examples/v2/P2P_Trading/confirm-request.json b/examples/v2/P2P_Trading/confirm-request.json deleted file mode 100644 index 755e8548..00000000 --- a/examples/v2/P2P_Trading/confirm-request.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "confirm", - "timestamp": "2024-10-04T10:25:00Z", - "message_id": "msg-confirm-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY" - } - ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ] - } - } -} - diff --git a/examples/v2/P2P_Trading/confirm-response.json b/examples/v2/P2P_Trading/confirm-response.json deleted file mode 100644 index f2ab1f87..00000000 --- a/examples/v2/P2P_Trading/confirm-response.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "on_confirm", - "timestamp": "2024-10-04T10:25:05Z", - "message_id": "msg-on-confirm-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:state": { - "@type": "beckn:State", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "PENDING" - } - } - } - ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "ACTIVE", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "inverterId": "inv-12345", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR", - "certification": { - "status": "Carbon Offset Certified", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - }, - "settlementCycles": [ - { - "cycleId": "settle-2024-10-04-001", - "startTime": "2024-10-04T00:00:00Z", - "endTime": "2024-10-04T23:59:59Z", - "status": "PENDING", - "amount": 0.0, - "currency": "USD" - } - ] - } - } - } -} - diff --git a/examples/v2/P2P_Trading/discover-response.json b/examples/v2/P2P_Trading/discover-response.json deleted file mode 100644 index d9d0fc9e..00000000 --- a/examples/v2/P2P_Trading/discover-response.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "on_discover", - "timestamp": "2024-10-04T10:00:05Z", - "message_id": "msg-on-discover-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "catalogs": [ - { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Catalog", - "beckn:id": "catalog-energy-001", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "Solar Energy Trading Catalog" - }, - "beckn:items": [ - { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Item", - "beckn:id": "energy-resource-solar-001", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "Solar Energy - 30.5 kWh", - "beckn:shortDesc": "Carbon Offset Certified Solar Energy", - "beckn:longDesc": "High-quality solar energy from verified source with carbon offset certification" - }, - "beckn:provider": { - "@type": "beckn:Provider", - "beckn:id": "provider-solar-farm-001" - }, - "beckn:itemAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyResource/v0.2/context.jsonld", - "@type": "EnergyResource", - "sourceType": "SOLAR", - "deliveryMode": "GRID_INJECTION", - "certificationStatus": "Carbon Offset Certified", - "meterId": "100200300", - "inverterId": "inv-12345", - "availableQuantity": 30.5, - "productionWindow": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - }, - "sourceVerification": { - "verified": true, - "verificationDate": "2024-09-01T00:00:00Z", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - }, - "productionAsynchronous": true - } - } - ], - "beckn:offers": [ - { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Offer", - "beckn:id": "offer-energy-001", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "Daily Settlement Solar Energy Offer" - }, - "beckn:provider": "provider-solar-farm-001", - "beckn:items": ["energy-resource-solar-001"], - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 0.15, - "schema:priceCurrency": "USD", - "schema:unitText": "kWh" - }, - "beckn:offerAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeOffer/v0.2/context.jsonld", - "@type": "EnergyTradeOffer", - "pricingModel": "PER_KWH", - "settlementType": "DAILY", - "wheelingCharges": { - "amount": 2.5, - "currency": "USD", - "description": "PG&E Grid Services wheeling charge" - }, - "minimumQuantity": 1.0, - "maximumQuantity": 100.0, - "validityWindow": { - "start": "2024-10-04T00:00:00Z", - "end": "2024-10-04T23:59:59Z" - } - } - } - ] - } - ] - } -} - diff --git a/examples/v2/P2P_Trading/init-request.json b/examples/v2/P2P_Trading/init-request.json deleted file mode 100644 index ad9b76fb..00000000 --- a/examples/v2/P2P_Trading/init-request.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "init", - "timestamp": "2024-10-04T10:20:00Z", - "message_id": "msg-init-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:stops": [ - { - "@type": "beckn:Stop", - "beckn:id": "stop-start-001", - "beckn:type": "START", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "100200300" - }, - "beckn:time": { - "@type": "beckn:Time", - "beckn:range": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - } - } - }, - { - "@type": "beckn:Stop", - "beckn:id": "stop-end-001", - "beckn:type": "END", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "98765456" - }, - "beckn:time": { - "@type": "beckn:Time", - "beckn:range": { - "start": "2024-10-04T10:00:00Z", - "end": "2024-10-04T18:00:00Z" - } - } - } - ] - } - ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ], - "beckn:billing": { - "@type": "beckn:Billing", - "beckn:name": "Energy Consumer", - "beckn:email": "consumer@example.com", - "beckn:phone": "+1-555-0100" - } - } - } -} - diff --git a/examples/v2/P2P_Trading/init-response.json b/examples/v2/P2P_Trading/init-response.json deleted file mode 100644 index dd9b5158..00000000 --- a/examples/v2/P2P_Trading/init-response.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "on_init", - "timestamp": "2024-10-04T10:20:05Z", - "message_id": "msg-on-init-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:stops": [ - { - "@type": "beckn:Stop", - "beckn:id": "stop-start-001", - "beckn:type": "START", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "100200300" - } - }, - { - "@type": "beckn:Stop", - "beckn:id": "stop-end-001", - "beckn:type": "END", - "beckn:location": { - "@type": "beckn:Location", - "beckn:address": "98765456" - } - } - ] - } - ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "PENDING", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "inverterId": "inv-12345", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR", - "certification": { - "status": "Carbon Offset Certified", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - } - } - } - } -} - diff --git a/examples/v2/P2P_Trading/select-request.json b/examples/v2/P2P_Trading/select-request.json deleted file mode 100644 index e891f620..00000000 --- a/examples/v2/P2P_Trading/select-request.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "select", - "timestamp": "2024-10-04T10:15:00Z", - "message_id": "msg-select-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - } - } - } -} - diff --git a/examples/v2/P2P_Trading/select-response.json b/examples/v2/P2P_Trading/select-response.json deleted file mode 100644 index 8527cffc..00000000 --- a/examples/v2/P2P_Trading/select-response.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "on_select", - "timestamp": "2024-10-04T10:15:05Z", - "message_id": "msg-on-select-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:quote": { - "@type": "beckn:Quotation", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 1.5, - "schema:priceCurrency": "USD", - "schema:unitText": "kWh" - }, - "beckn:breakup": [ - { - "@type": "beckn:Breakup", - "beckn:title": "Energy Cost (10 kWh @ $0.15/kWh)", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 1.5, - "schema:priceCurrency": "USD" - } - }, - { - "@type": "beckn:Breakup", - "beckn:title": "Wheeling Charges", - "beckn:price": { - "@type": "schema:PriceSpecification", - "schema:price": 2.5, - "schema:priceCurrency": "USD" - } - } - ] - } - } - } -} - diff --git a/examples/v2/P2P_Trading/status-response-completed.json b/examples/v2/P2P_Trading/status-response-completed.json deleted file mode 100644 index 6de2f0e3..00000000 --- a/examples/v2/P2P_Trading/status-response-completed.json +++ /dev/null @@ -1,161 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "on_status", - "timestamp": "2024-10-04T18:30:00Z", - "message_id": "msg-on-status-completed-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:state": { - "@type": "beckn:State", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "COMPLETED" - } - }, - "beckn:attributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeDelivery/v0.2/context.jsonld", - "@type": "EnergyTradeDelivery", - "deliveryStatus": "COMPLETED", - "deliveryMode": "GRID_INJECTION", - "deliveredQuantity": 10.0, - "deliveryStartTime": "2024-10-04T10:00:00Z", - "deliveryEndTime": "2024-10-04T18:00:00Z", - "meterReadings": [ - { - "timestamp": "2024-10-04T10:00:00Z", - "sourceReading": 1000.0, - "targetReading": 990.0, - "energyFlow": 0.0 - }, - { - "timestamp": "2024-10-04T12:00:00Z", - "sourceReading": 1000.5, - "targetReading": 990.3, - "energyFlow": 0.3 - }, - { - "timestamp": "2024-10-04T14:00:00Z", - "sourceReading": 1001.0, - "targetReading": 990.8, - "energyFlow": 0.5 - }, - { - "timestamp": "2024-10-04T16:00:00Z", - "sourceReading": 1002.0, - "targetReading": 991.5, - "energyFlow": 0.7 - }, - { - "timestamp": "2024-10-04T18:00:00Z", - "sourceReading": 1010.0, - "targetReading": 1000.0, - "energyFlow": 10.0 - } - ], - "telemetry": [ - { - "eventTime": "2024-10-04T18:00:00Z", - "metrics": [ - { - "name": "ENERGY", - "value": 10.0, - "unitCode": "KWH" - }, - { - "name": "POWER", - "value": 0.0, - "unitCode": "KW" - }, - { - "name": "VOLTAGE", - "value": 240.0, - "unitCode": "VLT" - } - ] - } - ], - "settlementCycleId": "settle-2024-10-04-001", - "lastUpdated": "2024-10-04T18:30:00Z" - } - } - ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "COMPLETED", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "inverterId": "inv-12345", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR", - "certification": { - "status": "Carbon Offset Certified", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - }, - "settlementCycles": [ - { - "cycleId": "settle-2024-10-04-001", - "startTime": "2024-10-04T00:00:00Z", - "endTime": "2024-10-04T23:59:59Z", - "status": "SETTLED", - "amount": 4.0, - "currency": "USD", - "breakdown": { - "energyCost": 1.5, - "wheelingCharges": 2.5 - } - } - ], - "lastUpdated": "2024-10-04T18:30:00Z" - } - } - } -} - diff --git a/examples/v2/P2P_Trading/status-response.json b/examples/v2/P2P_Trading/status-response.json deleted file mode 100644 index 9f0496d7..00000000 --- a/examples/v2/P2P_Trading/status-response.json +++ /dev/null @@ -1,145 +0,0 @@ -{ - "context": { - "version": "2.0.0", - "action": "on_status", - "timestamp": "2024-10-04T15:00:05Z", - "message_id": "msg-on-status-001", - "transaction_id": "txn-energy-001", - "bap_id": "bap.energy-consumer.com", - "bap_uri": "https://bap.energy-consumer.com", - "bpp_id": "bpp.energy-provider.com", - "bpp_uri": "https://bpp.energy-provider.com", - "ttl": "PT30S", - "domain": "energy-trade" - }, - "message": { - "order": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld", - "@type": "beckn:Order", - "beckn:id": "order-energy-001", - "beckn:items": [ - { - "beckn:id": "energy-resource-solar-001", - "quantity": { - "count": 10.0, - "unit": "kWh" - } - } - ], - "beckn:offers": [ - { - "beckn:id": "offer-energy-001" - } - ], - "beckn:provider": { - "beckn:id": "provider-solar-farm-001" - }, - "beckn:fulfillments": [ - { - "@type": "beckn:Fulfillment", - "beckn:id": "fulfillment-energy-001", - "beckn:type": "ENERGY_DELIVERY", - "beckn:state": { - "@type": "beckn:State", - "beckn:descriptor": { - "@type": "beckn:Descriptor", - "schema:name": "IN_PROGRESS" - } - }, - "beckn:attributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeDelivery/v0.2/context.jsonld", - "@type": "EnergyTradeDelivery", - "deliveryStatus": "IN_PROGRESS", - "deliveryMode": "GRID_INJECTION", - "deliveredQuantity": 9.8, - "deliveryStartTime": "2024-10-04T10:00:00Z", - "deliveryEndTime": null, - "meterReadings": [ - { - "timestamp": "2024-10-04T10:00:00Z", - "sourceReading": 1000.0, - "targetReading": 990.0, - "energyFlow": 10.0 - }, - { - "timestamp": "2024-10-04T12:00:00Z", - "sourceReading": 1000.5, - "targetReading": 990.3, - "energyFlow": 10.2 - }, - { - "timestamp": "2024-10-04T14:00:00Z", - "sourceReading": 1001.0, - "targetReading": 990.8, - "energyFlow": 10.2 - } - ], - "telemetry": [ - { - "eventTime": "2024-10-04T12:00:00Z", - "metrics": [ - { - "name": "ENERGY", - "value": 5.8, - "unitCode": "KWH" - }, - { - "name": "POWER", - "value": 2.5, - "unitCode": "KW" - }, - { - "name": "VOLTAGE", - "value": 240.0, - "unitCode": "VLT" - } - ] - } - ], - "settlementCycleId": "settle-2024-10-04-001", - "lastUpdated": "2024-10-04T15:30:00Z" - } - } - ], - "beckn:payments": [ - { - "@type": "beckn:Payment", - "beckn:id": "payment-energy-001", - "beckn:type": "ON-FULFILLMENT", - "beckn:status": "NOT-PAID", - "beckn:collected_by": "BPP" - } - ], - "beckn:orderAttributes": { - "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld", - "@type": "EnergyTradeContract", - "contractStatus": "ACTIVE", - "sourceMeterId": "100200300", - "targetMeterId": "98765456", - "inverterId": "inv-12345", - "contractedQuantity": 10.0, - "tradeStartTime": "2024-10-04T10:00:00Z", - "tradeEndTime": "2024-10-04T18:00:00Z", - "sourceType": "SOLAR", - "certification": { - "status": "Carbon Offset Certified", - "certificates": [ - "https://example.com/certs/solar-panel-cert.pdf" - ] - }, - "settlementCycles": [ - { - "cycleId": "settle-2024-10-04-001", - "startTime": "2024-10-04T00:00:00Z", - "endTime": "2024-10-04T23:59:59Z", - "status": "PENDING", - "amount": 0.0, - "currency": "USD" - } - ], - "lastUpdated": "2024-10-04T15:30:00Z" - } - } - } -} - diff --git a/plugins/degledgerrecorder/README.md b/plugins/degledgerrecorder/README.md new file mode 100644 index 00000000..9f8434dd --- /dev/null +++ b/plugins/degledgerrecorder/README.md @@ -0,0 +1,254 @@ +# DEG Ledger Recorder Plugin + +A Beckn-ONIX Step plugin that records trade data to the DEG Ledger after `on_confirm` calls. + +## Overview + +This plugin intercepts `on_confirm` beckn protocol messages and creates corresponding records in the DEG Ledger service by calling the `/ledger/put` API. It operates asynchronously (fire-and-forget) to avoid blocking the main request flow. + +## Features + +- Automatically detects `on_confirm` actions +- Maps beckn protocol fields to DEG Ledger format +- Creates one ledger record per order item +- Asynchronous operation (non-blocking) +- Configurable role (BUYER, SELLER, BUYER_DISCOM, SELLER_DISCOM) +- Idempotent requests using client reference +- **Beckn-style signature authentication** (same as beckn-onix outgoing messages) +- Detailed request/response logging for debugging + +## Building + +```bash +# From DEG repository root - builds Docker image with plugin included +./build/build-multiarch.sh --load +``` + +This builds the `onix-adapter-deg` Docker image with the plugin included. + +## Configuration + +Add to your ONIX handler configuration: + +```yaml +plugins: + steps: + - id: degledgerrecorder + config: + ledgerHost: "https://ledger.example.org" + role: "BUYER" # BUYER, SELLER, BUYER_DISCOM, or SELLER_DISCOM + enabled: "true" # Enable/disable the plugin + asyncTimeout: "5000" # Timeout in milliseconds + retryCount: "0" # Number of retries (0 = no retry) +steps: + - validateSign + - addRoute + - degledgerrecorder # Add after addRoute + - validateSchema +``` + +### Configuration Options + +#### Core Settings + +| Option | Required | Default | Description | +|--------|----------|---------|-------------| +| `ledgerHost` | Yes | - | Base URL of the DEG Ledger service | +| `role` | No | `BUYER` | Role for ledger records (see below) | +| `actions` | No | `on_confirm` | Comma-separated list of actions to trigger recording | +| `enabled` | No | `true` | Enable/disable plugin | +| `asyncTimeout` | No | `5000` | API call timeout (ms) | +| `retryCount` | No | `0` | Retry count for failed calls | +| `debugLogging` | No | `false` | Enable verbose request/response logging | + +#### Actions and Roles + +| Action | Ledger Endpoint | Supported Roles | Description | +|--------|-----------------|-----------------|-------------| +| `on_confirm` | `/ledger/put` | BUYER, SELLER | Records trade agreement | +| `on_status` | `/ledger/record` | BUYER_DISCOM, SELLER_DISCOM | Records meter readings/validation metrics | + +**Role behavior:** +- `BUYER` / `SELLER`: Platform roles, use `/ledger/put` for trade records +- `BUYER_DISCOM` / `SELLER_DISCOM`: Discom roles, use `/ledger/record` for validation metrics + - `BUYER_DISCOM`: Maps `allocatedEnergy` → `ACTUAL_PULLED` + - `SELLER_DISCOM`: Maps `allocatedEnergy` → `ACTUAL_PUSHED` + +#### Authentication Options + +The plugin supports two authentication methods: + +**Option 1: Beckn-style Signature Authentication (Recommended)** + +Uses the same ed25519 + BLAKE2b-512 signing mechanism as beckn-onix for outgoing messages. This generates an `Authorization` header with a cryptographic signature. + +| Option | Alias (simplekeymanager-style) | Required | Default | Description | +|--------|-------------------------------|----------|---------|-------------| +| `signingPrivateKey` | (same) | Yes* | - | Base64-encoded ed25519 private key seed | +| `subscriberId` | `networkParticipant` | Yes* | - | Subscriber ID (e.g., `bap.example.org`) | +| `uniqueKeyId` | `keyId` | Yes* | - | Unique key ID | +| `signatureValiditySeconds` | - | No | `30` | How long the signature is valid | + +*Required if using Beckn-style signing. If any signing field is set, all three must be set. + +**Config key aliases:** You can use the same config keys as `simplekeymanager` (`networkParticipant`, `keyId`) for easy copy-paste. + +**Option 2: Simple API Key Authentication** + +| Option | Required | Default | Description | +|--------|----------|---------|-------------| +| `apiKey` | No | - | API key for ledger service authentication | +| `authHeader` | No | `X-API-Key` | Header name for the API key | + +### Example 1: Zero-Config with Environment Variables (Recommended) + +If you already have environment variables set for `simplekeymanager`, the plugin will **automatically** use them - no additional config needed: + +```bash +# Environment variables (same as beckn-onix simplekeymanager) +export SIGNING_PRIVATE_KEY="" +export SUBSCRIBER_ID="bap.example.org" +export UNIQUE_KEY_ID="bap.example.org.k1" +``` + +```yaml +# Plugin config - no signing config needed! +plugins: + steps: + - id: degledgerrecorder + config: + ledgerHost: "https://ledger.example.org" + role: "BUYER" + # Signing config automatically loaded from env vars +``` + +This approach is **compatible with**: +- **HashiCorp Vault** - secrets injected via Vault Agent +- **Kubernetes Secrets** - mounted as env vars +- **Docker Secrets** - exposed as env vars +- **AWS Secrets Manager** - via ECS/Lambda env injection +- **Azure Key Vault** - via env injection + +### Example 2: Platform Recording (on_confirm only) + +```yaml +plugins: + steps: + - id: degledgerrecorder + config: + ledgerHost: "https://ledger.example.org" + role: "BUYER" # Platform role + actions: "on_confirm" # Default, records trade agreements + signingPrivateKey: "${SIGNING_PRIVATE_KEY}" + networkParticipant: "bap.example.org" + keyId: "bap.example.org.k1" +``` + +### Example 3: Discom Recording (on_status with meter readings) + +```yaml +plugins: + steps: + - id: degledgerrecorder + config: + ledgerHost: "https://ledger.example.org" + role: "BUYER_DISCOM" # Discom role for validation metrics + actions: "on_status" # Record meter readings + signingPrivateKey: "${SIGNING_PRIVATE_KEY}" + networkParticipant: "discom-buyer.example.org" + keyId: "discom-buyer.example.org.k1" +``` + +### Example 4: Both Actions (Platform + Discom in same instance) + +```yaml +plugins: + steps: + - id: degledgerrecorder + config: + ledgerHost: "https://ledger.example.org" + role: "BUYER_DISCOM" # Use discom role if handling both + actions: "on_confirm,on_status" # Handle both actions + signingPrivateKey: "${SIGNING_PRIVATE_KEY}" + networkParticipant: "example.org" + keyId: "example.org.k1" +``` + +**Note:** When `on_status` is enabled, the role must be `BUYER_DISCOM` or `SELLER_DISCOM`. + +### Environment Variables Reference + +| Variable | Description | +|----------|-------------| +| `SIGNING_PRIVATE_KEY` | Base64-encoded ed25519 private key seed | +| `SUBSCRIBER_ID` | Subscriber ID (e.g., `bap.example.org`) | +| `UNIQUE_KEY_ID` | Unique key ID (e.g., `bap.example.org.k1`) | + +### Generated Authorization Header + +``` +Authorization: Signature keyId="bap.example.org|bap.example.org.k1|ed25519",algorithm="ed25519",created="1706547600",expires="1706547630",headers="(created) (expires) digest",signature="" +``` + +### Vault Integration Example + +```hcl +# Vault Agent template +template { + contents = < 0 { + fmt.Printf("[DEGLedgerRecorder] Retry attempt %d/%d for order_item_id=%s\n", + attempt, c.retryCount, record.OrderItemID) + } + + resp, err := c.doPutRequest(ctx, record, attempt) + if err == nil { + return resp, nil + } + + lastErr = err + + // Don't retry on context cancellation + if ctx.Err() != nil { + return nil, fmt.Errorf("context cancelled: %w", ctx.Err()) + } + + // Simple backoff for retries + if attempt < c.retryCount { + backoff := time.Duration(attempt+1) * 100 * time.Millisecond + fmt.Printf("[DEGLedgerRecorder] Backing off for %v before retry\n", backoff) + time.Sleep(backoff) + } + } + + return nil, lastErr +} + +// RecordActuals sends meter readings/validation metrics to the ledger RECORD API. +// This is for discom roles (BUYER_DISCOM, SELLER_DISCOM). +func (c *LedgerClient) RecordActuals(ctx context.Context, record LedgerRecordRequest) (*LedgerPutResponse, error) { + var lastErr error + + for attempt := 0; attempt <= c.retryCount; attempt++ { + if attempt > 0 { + fmt.Printf("[DEGLedgerRecorder] Retry attempt %d/%d for order_item_id=%s (record actuals)\n", + attempt, c.retryCount, record.OrderItemID) + } + + resp, err := c.doRecordRequest(ctx, record, attempt) + if err == nil { + return resp, nil + } + + lastErr = err + + // Don't retry on context cancellation + if ctx.Err() != nil { + return nil, fmt.Errorf("context cancelled: %w", ctx.Err()) + } + + // Don't retry on 404 (record not found) + if strings.Contains(err.Error(), "404") { + return nil, err + } + + // Simple backoff for retries + if attempt < c.retryCount { + backoff := time.Duration(attempt+1) * 100 * time.Millisecond + fmt.Printf("[DEGLedgerRecorder] Backing off for %v before retry\n", backoff) + time.Sleep(backoff) + } + } + + return nil, lastErr +} + +// doRecordRequest performs a single request to the ledger RECORD API. +func (c *LedgerClient) doRecordRequest(ctx context.Context, record LedgerRecordRequest, attempt int) (*LedgerPutResponse, error) { + // Generate unique request ID for correlation + requestID := uuid.New().String()[:8] + startTime := time.Now() + + // Serialize the request body + body, err := json.Marshal(record) + if err != nil { + return nil, fmt.Errorf("failed to marshal ledger record request: %w", err) + } + + // Create the HTTP request + url := fmt.Sprintf("%s/ledger/record", c.baseURL) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + // Set headers + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + req.Header.Set("X-Request-ID", requestID) + + // Add authentication header + if c.signer != nil && c.signer.IsConfigured() { + authHeader, err := c.signer.GenerateAuthHeader(body) + if err != nil { + return nil, fmt.Errorf("failed to generate Authorization header: %w", err) + } + req.Header.Set("Authorization", authHeader) + } else if c.apiKey != "" { + req.Header.Set(c.authHeader, c.apiKey) + } + + // Log request details + c.logRecordRequest(requestID, req, record, attempt) + + // Execute the request + resp, err := c.httpClient.Do(req) + duration := time.Since(startTime) + + if err != nil { + c.logError(requestID, "HTTP request failed", err, duration) + return nil, fmt.Errorf("ledger record request failed: %w", err) + } + defer resp.Body.Close() + + // Read the response body + respBody, err := io.ReadAll(resp.Body) + if err != nil { + c.logError(requestID, "Failed to read response body", err, duration) + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + // Log response details + c.logResponse(requestID, resp, respBody, duration) + + // Handle different status codes + switch resp.StatusCode { + case http.StatusOK: + var ledgerResp LedgerPutResponse + if err := json.Unmarshal(respBody, &ledgerResp); err != nil { + return nil, fmt.Errorf("failed to parse success response: %w", err) + } + return &ledgerResp, nil + + case http.StatusNotFound: + return nil, fmt.Errorf("ledger record not found (404): %s", string(respBody)) + + case http.StatusBadRequest, http.StatusUnauthorized, http.StatusForbidden, http.StatusConflict: + var errResp LedgerErrorResponse + if err := json.Unmarshal(respBody, &errResp); err != nil { + return nil, fmt.Errorf("ledger API error (status %d): %s", resp.StatusCode, string(respBody)) + } + return nil, fmt.Errorf("ledger API error (status %d, code %s): %s", resp.StatusCode, errResp.Code, errResp.Message) + + default: + return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(respBody)) + } +} + +// doPutRequest performs a single PUT request to the ledger API. +func (c *LedgerClient) doPutRequest(ctx context.Context, record LedgerPutRequest, attempt int) (*LedgerPutResponse, error) { + // Generate unique request ID for correlation + requestID := uuid.New().String()[:8] + startTime := time.Now() + + // Serialize the request body + body, err := json.Marshal(record) + if err != nil { + return nil, fmt.Errorf("failed to marshal ledger request: %w", err) + } + + // Create the HTTP request + url := fmt.Sprintf("%s/ledger/put", c.baseURL) + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(body)) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + + // Set headers + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Accept", "application/json") + req.Header.Set("X-Request-ID", requestID) + + // Add authentication header + // Priority: Beckn signature > API Key + if c.signer != nil && c.signer.IsConfigured() { + // Generate Beckn-style Authorization header with signature + authHeader, err := c.signer.GenerateAuthHeader(body) + if err != nil { + return nil, fmt.Errorf("failed to generate Authorization header: %w", err) + } + req.Header.Set("Authorization", authHeader) + } else if c.apiKey != "" { + // Fall back to simple API key authentication + req.Header.Set(c.authHeader, c.apiKey) + } + + // Log request details + c.logRequest(requestID, req, record, attempt) + + // Execute the request + resp, err := c.httpClient.Do(req) + duration := time.Since(startTime) + + if err != nil { + c.logError(requestID, "HTTP request failed", err, duration) + return nil, fmt.Errorf("ledger request failed: %w", err) + } + defer resp.Body.Close() + + // Read the response body + respBody, err := io.ReadAll(resp.Body) + if err != nil { + c.logError(requestID, "Failed to read response body", err, duration) + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + // Log response details + c.logResponse(requestID, resp, respBody, duration) + + // Handle different status codes + switch resp.StatusCode { + case http.StatusOK: + var ledgerResp LedgerPutResponse + if err := json.Unmarshal(respBody, &ledgerResp); err != nil { + return nil, fmt.Errorf("failed to parse success response: %w", err) + } + return &ledgerResp, nil + + case http.StatusBadRequest, http.StatusUnauthorized, http.StatusForbidden, http.StatusConflict: + var errResp LedgerErrorResponse + if err := json.Unmarshal(respBody, &errResp); err != nil { + return nil, fmt.Errorf("ledger API error (status %d): %s", resp.StatusCode, string(respBody)) + } + return nil, fmt.Errorf("ledger API error (status %d, code %s): %s", resp.StatusCode, errResp.Code, errResp.Message) + + default: + return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(respBody)) + } +} + +// logRequest logs the full HTTP request details. +func (c *LedgerClient) logRequest(requestID string, req *http.Request, record LedgerPutRequest, attempt int) { + // Build headers map (masking sensitive values) + headers := make(map[string]string) + for key, values := range req.Header { + value := strings.Join(values, ", ") + // Mask auth-related headers + if strings.Contains(strings.ToLower(key), "auth") || + strings.Contains(strings.ToLower(key), "api-key") || + strings.Contains(strings.ToLower(key), "x-api-key") || + key == c.authHeader { + if len(value) > 8 { + headers[key] = value[:4] + "****" + value[len(value)-4:] + } else { + headers[key] = "****" + } + } else { + headers[key] = value + } + } + + fmt.Println("") + fmt.Println("╔════════════════════════════════════════════════════════════════════╗") + fmt.Println("║ DEGLedgerRecorder - OUTGOING REQUEST ║") + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Printf("║ Request ID: %s\n", requestID) + fmt.Printf("║ Timestamp: %s\n", time.Now().UTC().Format(time.RFC3339)) + fmt.Printf("║ Attempt: %d/%d\n", attempt+1, c.retryCount+1) + fmt.Printf("║ Method: %s\n", req.Method) + fmt.Printf("║ URL: %s\n", req.URL.String()) + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Println("║ HEADERS:") + for k, v := range headers { + fmt.Printf("║ %s: %s\n", k, v) + } + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Println("║ REQUEST BODY (JSON):") + + // Pretty print the request body + prettyBody, err := json.MarshalIndent(record, "║ ", " ") + if err != nil { + fmt.Printf("║ (error formatting body: %v)\n", err) + } else { + lines := strings.Split(string(prettyBody), "\n") + for _, line := range lines { + fmt.Printf("║ %s\n", line) + } + } + fmt.Println("╚════════════════════════════════════════════════════════════════════╝") +} + +// logRecordRequest logs the full HTTP request details for /ledger/record. +func (c *LedgerClient) logRecordRequest(requestID string, req *http.Request, record LedgerRecordRequest, attempt int) { + // Build headers map (masking sensitive values) + headers := make(map[string]string) + for key, values := range req.Header { + value := strings.Join(values, ", ") + // Mask auth-related headers + if strings.Contains(strings.ToLower(key), "auth") || + strings.Contains(strings.ToLower(key), "api-key") || + strings.Contains(strings.ToLower(key), "x-api-key") || + key == c.authHeader { + if len(value) > 8 { + headers[key] = value[:4] + "****" + value[len(value)-4:] + } else { + headers[key] = "****" + } + } else { + headers[key] = value + } + } + + fmt.Println("") + fmt.Println("╔════════════════════════════════════════════════════════════════════╗") + fmt.Println("║ DEGLedgerRecorder - OUTGOING REQUEST (RECORD) ║") + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Printf("║ Request ID: %s\n", requestID) + fmt.Printf("║ Timestamp: %s\n", time.Now().UTC().Format(time.RFC3339)) + fmt.Printf("║ Attempt: %d/%d\n", attempt+1, c.retryCount+1) + fmt.Printf("║ Method: %s\n", req.Method) + fmt.Printf("║ URL: %s\n", req.URL.String()) + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Println("║ HEADERS:") + for k, v := range headers { + fmt.Printf("║ %s: %s\n", k, v) + } + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Println("║ REQUEST BODY (JSON):") + + // Pretty print the request body + prettyBody, err := json.MarshalIndent(record, "║ ", " ") + if err != nil { + fmt.Printf("║ (error formatting body: %v)\n", err) + } else { + lines := strings.Split(string(prettyBody), "\n") + for _, line := range lines { + fmt.Printf("║ %s\n", line) + } + } + fmt.Println("╚════════════════════════════════════════════════════════════════════╝") +} + +// logResponse logs the full HTTP response details. +func (c *LedgerClient) logResponse(requestID string, resp *http.Response, body []byte, duration time.Duration) { + // Build headers map + headers := make(map[string]string) + for key, values := range resp.Header { + headers[key] = strings.Join(values, ", ") + } + + // Determine status emoji + statusEmoji := "✓" + if resp.StatusCode >= 400 { + statusEmoji = "✗" + } + + fmt.Println("") + fmt.Println("╔════════════════════════════════════════════════════════════════════╗") + fmt.Printf("║ DEGLedgerRecorder - RESPONSE %s ║\n", statusEmoji) + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Printf("║ Request ID: %s\n", requestID) + fmt.Printf("║ Timestamp: %s\n", time.Now().UTC().Format(time.RFC3339)) + fmt.Printf("║ Duration: %v\n", duration) + fmt.Printf("║ Status: %d %s\n", resp.StatusCode, http.StatusText(resp.StatusCode)) + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Println("║ RESPONSE HEADERS:") + for k, v := range headers { + fmt.Printf("║ %s: %s\n", k, v) + } + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Println("║ RESPONSE BODY:") + + // Try to pretty print JSON, fall back to raw if not valid JSON + var prettyBody bytes.Buffer + if err := json.Indent(&prettyBody, body, "║ ", " "); err == nil { + lines := strings.Split(prettyBody.String(), "\n") + for _, line := range lines { + fmt.Printf("║ %s\n", line) + } + } else { + // Not JSON or invalid JSON, print raw (truncated if too long) + bodyStr := string(body) + if len(bodyStr) > 2000 { + bodyStr = bodyStr[:2000] + "... (truncated)" + } + fmt.Printf("║ %s\n", bodyStr) + } + fmt.Println("╚════════════════════════════════════════════════════════════════════╝") +} + +// logError logs an error that occurred during the request. +func (c *LedgerClient) logError(requestID string, message string, err error, duration time.Duration) { + fmt.Println("") + fmt.Println("╔════════════════════════════════════════════════════════════════════╗") + fmt.Println("║ DEGLedgerRecorder - ERROR ✗ ║") + fmt.Println("╠════════════════════════════════════════════════════════════════════╣") + fmt.Printf("║ Request ID: %s\n", requestID) + fmt.Printf("║ Timestamp: %s\n", time.Now().UTC().Format(time.RFC3339)) + fmt.Printf("║ Duration: %v\n", duration) + fmt.Printf("║ Error: %s\n", message) + fmt.Printf("║ Details: %v\n", err) + fmt.Println("╚════════════════════════════════════════════════════════════════════╝") +} + +// Close releases resources held by the client. +func (c *LedgerClient) Close() error { + c.httpClient.CloseIdleConnections() + return nil +} diff --git a/plugins/degledgerrecorder/cmd/plugin.go b/plugins/degledgerrecorder/cmd/plugin.go new file mode 100644 index 00000000..a8d668ea --- /dev/null +++ b/plugins/degledgerrecorder/cmd/plugin.go @@ -0,0 +1,29 @@ +// Package main provides the plugin entry point for the DEG Ledger Recorder plugin. +// This file is compiled as a Go plugin (.so) and loaded by beckn-onix at runtime. +package main + +import ( + "context" + + "github.com/beckn-one/beckn-onix/pkg/plugin/definition" + degledgerrecorder "github.com/beckn-one/deg/plugins/degledgerrecorder" +) + +// provider implements the StepProvider interface for plugin loading. +type provider struct{} + +// New creates a new DEGLedgerRecorder step instance. +// It returns the step, a cleanup function, and any error. +func (p provider) New(ctx context.Context, cfg map[string]string) (definition.Step, func(), error) { + recorder, err := degledgerrecorder.New(cfg) + if err != nil { + return nil, nil, err + } + + // Return the recorder, its Close method as cleanup, and no error + return recorder, recorder.Close, nil +} + +// Provider is the exported symbol that beckn-onix plugin manager looks up. +// It must be a package-level variable named "Provider". +var Provider = provider{} diff --git a/plugins/degledgerrecorder/config.go b/plugins/degledgerrecorder/config.go new file mode 100644 index 00000000..763f05a0 --- /dev/null +++ b/plugins/degledgerrecorder/config.go @@ -0,0 +1,281 @@ +package degledgerrecorder + +import ( + "fmt" + "os" + "strconv" + "strings" + "time" +) + +// Environment variable names for signing configuration. +// These are the same env vars typically used by beckn-onix simplekeymanager, +// allowing single-source-of-truth configuration. +// Also compatible with Vault Agent, K8s secrets, etc. +const ( + EnvSigningPrivateKey = "SIGNING_PRIVATE_KEY" + EnvSubscriberID = "SUBSCRIBER_ID" + EnvUniqueKeyID = "UNIQUE_KEY_ID" +) + +// Supported actions for ledger recording +const ( + ActionOnConfirm = "on_confirm" + ActionOnStatus = "on_status" +) + +// Config holds the configuration for the DEG Ledger Recorder plugin. +type Config struct { + // LedgerHost is the base URL of the DEG Ledger service (e.g., "https://ledger.example.org") + LedgerHost string + + // Role is the ledger role for this platform (BUYER, SELLER, BUYER_DISCOM, SELLER_DISCOM) + Role string + + // Actions is a list of beckn actions that trigger ledger recording. + // Supported: "on_confirm" (trade records via /ledger/put), "on_status" (meter readings via /ledger/record) + // Default: ["on_confirm"] + Actions []string + + // Enabled controls whether the plugin is active + Enabled bool + + // AsyncTimeout is the timeout for async ledger API calls in milliseconds + AsyncTimeout time.Duration + + // RetryCount is the number of retries for failed ledger calls (0 = no retry) + RetryCount int + + // APIKey is an optional API key for ledger service authentication (simple auth) + APIKey string + + // AuthHeader is the header name for the API key (default: X-API-Key) + AuthHeader string + + // DebugLogging enables verbose request/response logging + DebugLogging bool + + // --- Beckn-style Signature Authentication --- + // When configured, generates Authorization header using the same signing mechanism + // as beckn-onix (ed25519 + BLAKE2b-512) + + // SigningPrivateKey is the base64-encoded ed25519 private key seed for signing + // This should be the same key used by beckn-onix for signing outgoing messages + SigningPrivateKey string + + // SubscriberID is the subscriber ID used in the Authorization header keyId + // Format in header: keyId="||ed25519" + SubscriberID string + + // UniqueKeyID is the unique key identifier used in the Authorization header keyId + UniqueKeyID string + + // SignatureValiditySeconds is how long the signature is valid (default: 30 seconds) + SignatureValiditySeconds int + + // SigningFromEnv indicates if signing config was loaded from environment variables + // (used for logging purposes) + SigningFromEnv bool +} + +// DefaultConfig returns a Config with sensible defaults. +func DefaultConfig() *Config { + return &Config{ + LedgerHost: "", + Role: "BUYER", + Actions: []string{ActionOnConfirm}, // Default: only on_confirm + Enabled: true, + AsyncTimeout: 5 * time.Second, + RetryCount: 0, + APIKey: "", + AuthHeader: "X-API-Key", + DebugLogging: false, + SigningPrivateKey: "", + SubscriberID: "", + UniqueKeyID: "", + SignatureValiditySeconds: 30, + } +} + +// ParseConfig parses the plugin configuration map into a Config struct. +func ParseConfig(cfg map[string]string) (*Config, error) { + config := DefaultConfig() + + if host, ok := cfg["ledgerHost"]; ok && host != "" { + config.LedgerHost = host + } + if config.LedgerHost == "" { + return nil, fmt.Errorf("ledgerHost is required") + } + + if role, ok := cfg["role"]; ok && role != "" { + if !isValidRole(role) { + return nil, fmt.Errorf("invalid role: %s (must be BUYER, SELLER, BUYER_DISCOM, or SELLER_DISCOM)", role) + } + config.Role = role + } + + // Parse actions (comma-separated list) + if actions, ok := cfg["actions"]; ok && actions != "" { + actionList := strings.Split(actions, ",") + config.Actions = make([]string, 0, len(actionList)) + for _, action := range actionList { + action = strings.TrimSpace(action) + if action != "" { + if !isValidAction(action) { + return nil, fmt.Errorf("invalid action: %s (must be on_confirm or on_status)", action) + } + config.Actions = append(config.Actions, action) + } + } + } + + if enabled, ok := cfg["enabled"]; ok { + config.Enabled = enabled == "true" || enabled == "1" + } + + if timeout, ok := cfg["asyncTimeout"]; ok && timeout != "" { + ms, err := strconv.Atoi(timeout) + if err != nil { + return nil, fmt.Errorf("invalid asyncTimeout: %s", timeout) + } + config.AsyncTimeout = time.Duration(ms) * time.Millisecond + } + + if retry, ok := cfg["retryCount"]; ok && retry != "" { + count, err := strconv.Atoi(retry) + if err != nil { + return nil, fmt.Errorf("invalid retryCount: %s", retry) + } + config.RetryCount = count + } + + if apiKey, ok := cfg["apiKey"]; ok { + config.APIKey = apiKey + } + + if authHeader, ok := cfg["authHeader"]; ok && authHeader != "" { + config.AuthHeader = authHeader + } + + if debug, ok := cfg["debugLogging"]; ok { + config.DebugLogging = debug == "true" || debug == "1" + } + + // Beckn-style signature authentication + // Priority: explicit config > simplekeymanager-style config > environment variables + // + // Supported config key aliases (for compatibility with simplekeymanager): + // signingPrivateKey (same in both) + // subscriberId OR networkParticipant + // uniqueKeyId OR keyId + + // Signing private key (same name in both styles) + if signingKey, ok := cfg["signingPrivateKey"]; ok && signingKey != "" { + config.SigningPrivateKey = signingKey + } + + // Subscriber ID: check both "subscriberId" and "networkParticipant" (simplekeymanager style) + if subscriberID, ok := cfg["subscriberId"]; ok && subscriberID != "" { + config.SubscriberID = subscriberID + } else if networkParticipant, ok := cfg["networkParticipant"]; ok && networkParticipant != "" { + config.SubscriberID = networkParticipant + } + + // Unique Key ID: check both "uniqueKeyId" and "keyId" (simplekeymanager style) + if uniqueKeyID, ok := cfg["uniqueKeyId"]; ok && uniqueKeyID != "" { + config.UniqueKeyID = uniqueKeyID + } else if keyId, ok := cfg["keyId"]; ok && keyId != "" { + config.UniqueKeyID = keyId + } + + if validity, ok := cfg["signatureValiditySeconds"]; ok && validity != "" { + seconds, err := strconv.Atoi(validity) + if err != nil { + return nil, fmt.Errorf("invalid signatureValiditySeconds: %s", validity) + } + config.SignatureValiditySeconds = seconds + } + + // Fallback to environment variables if not explicitly configured + // This allows reusing the same env vars as beckn-onix simplekeymanager + // and is compatible with Vault Agent, K8s secrets, etc. + signingFromEnv := false + if config.SigningPrivateKey == "" { + if envVal := os.Getenv(EnvSigningPrivateKey); envVal != "" { + config.SigningPrivateKey = envVal + signingFromEnv = true + } + } + if config.SubscriberID == "" { + if envVal := os.Getenv(EnvSubscriberID); envVal != "" { + config.SubscriberID = envVal + signingFromEnv = true + } + } + if config.UniqueKeyID == "" { + if envVal := os.Getenv(EnvUniqueKeyID); envVal != "" { + config.UniqueKeyID = envVal + signingFromEnv = true + } + } + + // Store whether config came from env for logging purposes + config.SigningFromEnv = signingFromEnv + + // Validate signing config: if any signing field is set, all must be set + signingConfigured := config.SigningPrivateKey != "" || config.SubscriberID != "" || config.UniqueKeyID != "" + if signingConfigured { + if config.SigningPrivateKey == "" { + return nil, fmt.Errorf("signingPrivateKey is required when Beckn signing is configured (set via config or %s env var)", EnvSigningPrivateKey) + } + if config.SubscriberID == "" { + return nil, fmt.Errorf("subscriberId is required when Beckn signing is configured (set via config or %s env var)", EnvSubscriberID) + } + if config.UniqueKeyID == "" { + return nil, fmt.Errorf("uniqueKeyId is required when Beckn signing is configured (set via config or %s env var)", EnvUniqueKeyID) + } + } + + return config, nil +} + +// isValidRole checks if the provided role is valid for the ledger API. +func isValidRole(role string) bool { + validRoles := map[string]bool{ + "BUYER": true, + "SELLER": true, + "BUYER_DISCOM": true, + "SELLER_DISCOM": true, + } + return validRoles[role] +} + +// isValidAction checks if the provided action is supported. +func isValidAction(action string) bool { + validActions := map[string]bool{ + ActionOnConfirm: true, + ActionOnStatus: true, + } + return validActions[action] +} + +// IsActionEnabled checks if the given action is enabled in the config. +func (c *Config) IsActionEnabled(action string) bool { + for _, a := range c.Actions { + if a == action { + return true + } + } + return false +} + +// IsDiscomRole returns true if the configured role is a discom role. +func (c *Config) IsDiscomRole() bool { + return c.Role == "BUYER_DISCOM" || c.Role == "SELLER_DISCOM" +} + +// IsBuyerSide returns true if the role is buyer or buyer discom. +func (c *Config) IsBuyerSide() bool { + return c.Role == "BUYER" || c.Role == "BUYER_DISCOM" +} diff --git a/plugins/degledgerrecorder/mapper.go b/plugins/degledgerrecorder/mapper.go new file mode 100644 index 00000000..13397c33 --- /dev/null +++ b/plugins/degledgerrecorder/mapper.go @@ -0,0 +1,533 @@ +package degledgerrecorder + +import ( + "encoding/json" + "fmt" + "log" + "strings" +) + +// OnConfirmPayload represents the structure of an on_confirm beckn message. +type OnConfirmPayload struct { + Context OnConfirmContext `json:"context"` + Message OnConfirmMessage `json:"message"` +} + +// OnConfirmContext represents the context portion of the on_confirm message. +type OnConfirmContext struct { + Version string `json:"version"` + Action string `json:"action"` + Timestamp string `json:"timestamp"` + MessageID string `json:"message_id"` + TransactionID string `json:"transaction_id"` + BapID string `json:"bap_id"` + BapURI string `json:"bap_uri"` + BppID string `json:"bpp_id"` + BppURI string `json:"bpp_uri"` + TTL string `json:"ttl"` + Domain string `json:"domain"` +} + +// OnConfirmMessage represents the message portion of the on_confirm message. +type OnConfirmMessage struct { + Order Order `json:"order"` +} + +// Order represents the order structure in the on_confirm message. +// Using map for flexible JSON-LD parsing. +type Order struct { + ID string `json:"beckn:id"` + OrderStatus string `json:"beckn:orderStatus"` + Seller string `json:"beckn:seller"` + Buyer map[string]interface{} `json:"beckn:buyer"` + OrderAttributes map[string]interface{} `json:"beckn:orderAttributes"` + OrderItems []OrderItem `json:"beckn:orderItems"` + Fulfillment map[string]interface{} `json:"beckn:fulfillment"` +} + +// OrderItem represents an item in the order. +type OrderItem struct { + OrderedItem string `json:"beckn:orderedItem"` + Quantity Quantity `json:"beckn:quantity"` + OrderItemAttributes map[string]interface{} `json:"beckn:orderItemAttributes"` + AcceptedOffer AcceptedOffer `json:"beckn:acceptedOffer"` +} + +// Quantity represents quantity information. +type Quantity struct { + UnitQuantity float64 `json:"unitQuantity"` + UnitText string `json:"unitText"` +} + +// AcceptedOffer represents the accepted offer in an order item. +type AcceptedOffer struct { + ID string `json:"beckn:id"` + Descriptor map[string]interface{} `json:"beckn:descriptor"` + Provider string `json:"beckn:provider"` + Items []string `json:"beckn:items"` + OfferAttributes map[string]interface{} `json:"beckn:offerAttributes"` +} + +// LedgerPutRequest represents the request body for the ledger PUT API. +type LedgerPutRequest struct { + Role string `json:"role"` + TransactionID string `json:"transactionId"` + OrderItemID string `json:"orderItemId"` + PlatformIDBuyer string `json:"platformIdBuyer"` + PlatformIDSeller string `json:"platformIdSeller"` + DiscomIDBuyer string `json:"discomIdBuyer,omitempty"` + DiscomIDSeller string `json:"discomIdSeller,omitempty"` + BuyerID string `json:"buyerId,omitempty"` + SellerID string `json:"sellerId,omitempty"` + TradeTime string `json:"tradeTime,omitempty"` + DeliveryStartTime string `json:"deliveryStartTime,omitempty"` + DeliveryEndTime string `json:"deliveryEndTime,omitempty"` + TradeDetails []TradeDetail `json:"tradeDetails,omitempty"` + ClientReference string `json:"clientReference,omitempty"` +} + +// TradeDetail represents a single trade detail entry. +type TradeDetail struct { + TradeQty float64 `json:"tradeQty"` + TradeType string `json:"tradeType"` + TradeUnit string `json:"tradeUnit"` +} + +// ------------------------- +// on_status → /ledger/record mapping +// ------------------------- + +// LedgerRecordRequest represents the request body for the ledger RECORD API (discom actuals). +type LedgerRecordRequest struct { + Role string `json:"role"` + TransactionID string `json:"transactionId"` + OrderItemID string `json:"orderItemId"` + BuyerFulfillmentValidationMetrics []ValidationMetric `json:"buyerFulfillmentValidationMetrics,omitempty"` + SellerFulfillmentValidationMetrics []ValidationMetric `json:"sellerFulfillmentValidationMetrics,omitempty"` + // StatusBuyerDiscom string `json:"statusBuyerDiscom,omitempty"` // Future: leave empty for now + // StatusSellerDiscom string `json:"statusSellerDiscom,omitempty"` // Future: leave empty for now + ClientReference string `json:"clientReference,omitempty"` +} + +// ValidationMetric represents a fulfillment validation metric. +type ValidationMetric struct { + ValidationMetricType string `json:"validationMetricType"` + ValidationMetricValue float64 `json:"validationMetricValue"` +} + +// OnStatusPayload represents the structure of an on_status beckn message. +// Uses the same context structure as on_confirm. +type OnStatusPayload struct { + Context OnConfirmContext `json:"context"` // Reuse context structure + Message OnStatusMessage `json:"message"` +} + +// OnStatusMessage represents the message portion of the on_status message. +type OnStatusMessage struct { + Order OnStatusOrder `json:"order"` +} + +// OnStatusOrder represents the order in on_status with fulfillment attributes. +type OnStatusOrder struct { + ID string `json:"beckn:id"` + OrderStatus string `json:"beckn:orderStatus"` + Seller string `json:"beckn:seller"` + Buyer map[string]interface{} `json:"beckn:buyer"` + OrderAttributes map[string]interface{} `json:"beckn:orderAttributes"` + OrderItems []OnStatusOrderItem `json:"beckn:orderItems"` +} + +// OnStatusOrderItem represents an order item in on_status with fulfillment data. +type OnStatusOrderItem struct { + OrderedItem string `json:"beckn:orderedItem"` + Quantity Quantity `json:"beckn:quantity"` + OrderItemAttributes map[string]interface{} `json:"beckn:orderItemAttributes"` + AcceptedOffer AcceptedOffer `json:"beckn:acceptedOffer"` +} + +// MeterReading represents a meter reading from fulfillmentAttributes. +type MeterReading struct { + TimeWindow map[string]interface{} `json:"beckn:timeWindow"` + ConsumedEnergy float64 `json:"consumedEnergy"` + ProducedEnergy float64 `json:"producedEnergy"` + AllocatedEnergy float64 `json:"allocatedEnergy"` + Unit string `json:"unit"` +} + +// ParseOnConfirm parses the raw JSON body into an OnConfirmPayload. +func ParseOnConfirm(body []byte) (*OnConfirmPayload, error) { + var payload OnConfirmPayload + if err := json.Unmarshal(body, &payload); err != nil { + return nil, fmt.Errorf("failed to parse on_confirm payload: %w", err) + } + return &payload, nil +} + +// MapToLedgerRecords converts an on_confirm payload to ledger PUT requests. +// Returns one LedgerPutRequest per order item. +func MapToLedgerRecords(payload *OnConfirmPayload, role string) []LedgerPutRequest { + records := make([]LedgerPutRequest, 0, len(payload.Message.Order.OrderItems)) + + for _, item := range payload.Message.Order.OrderItems { + // Extract delivery window times + deliveryStartTime := extractTimeWindowField(item.AcceptedOffer.OfferAttributes, "schema:startTime") + deliveryEndTime := extractTimeWindowField(item.AcceptedOffer.OfferAttributes, "schema:endTime") + + // Log warnings if delivery times are missing + if deliveryStartTime == "" { + log.Printf("WARNING: deliveryStartTime not found in payload for offer %s (txn: %s)", + item.AcceptedOffer.ID, payload.Context.TransactionID) + } + if deliveryEndTime == "" { + log.Printf("WARNING: deliveryEndTime not found in payload for offer %s (txn: %s)", + item.AcceptedOffer.ID, payload.Context.TransactionID) + } + + record := LedgerPutRequest{ + Role: role, + TransactionID: payload.Context.TransactionID, + OrderItemID: item.AcceptedOffer.ID, + PlatformIDBuyer: payload.Context.BapID, + PlatformIDSeller: payload.Context.BppID, + DiscomIDBuyer: extractBuyerUtilityID(payload.Message.Order.Buyer), + DiscomIDSeller: extractSellerUtilityID(item.OrderItemAttributes), + BuyerID: extractBuyerID(payload.Message.Order.Buyer), + SellerID: extractSellerID(item.OrderItemAttributes), + TradeTime: payload.Context.Timestamp, + DeliveryStartTime: deliveryStartTime, + DeliveryEndTime: deliveryEndTime, + TradeDetails: mapTradeDetails(item), + ClientReference: generateClientReference(payload.Context.TransactionID, item.AcceptedOffer.ID), + } + records = append(records, record) + } + + return records +} + +// extractStringField extracts a string field from a map. +func extractStringField(m map[string]interface{}, key string) string { + if m == nil { + return "" + } + if v, ok := m[key]; ok { + if s, ok := v.(string); ok { + return s + } + } + return "" +} + +// extractBuyerID extracts the buyer's meterId from buyerAttributes. +// Path: buyer -> beckn:buyerAttributes -> meterId +func extractBuyerID(buyer map[string]interface{}) string { + if buyer == nil { + return "" + } + // Navigate to buyerAttributes + buyerAttrs, ok := buyer["beckn:buyerAttributes"] + if !ok { + return "" + } + buyerAttrsMap, ok := buyerAttrs.(map[string]interface{}) + if !ok { + return "" + } + // Extract meterId + if meterId, ok := buyerAttrsMap["meterId"]; ok { + if s, ok := meterId.(string); ok { + return s + } + } + return "" +} + +// extractSellerID extracts the seller's meterId from orderItemAttributes.providerAttributes. +// Path: orderItemAttributes -> providerAttributes -> meterId +func extractSellerID(orderItemAttrs map[string]interface{}) string { + if orderItemAttrs == nil { + return "" + } + // Navigate to providerAttributes + providerAttrs, ok := orderItemAttrs["providerAttributes"] + if !ok { + return "" + } + providerAttrsMap, ok := providerAttrs.(map[string]interface{}) + if !ok { + return "" + } + // Extract meterId + if meterId, ok := providerAttrsMap["meterId"]; ok { + if s, ok := meterId.(string); ok { + return s + } + } + return "" +} + +// extractBuyerUtilityID extracts the buyer's utilityId (discom ID) from buyerAttributes. +// Path: buyer -> beckn:buyerAttributes -> utilityId +func extractBuyerUtilityID(buyer map[string]interface{}) string { + if buyer == nil { + return "" + } + buyerAttrs, ok := buyer["beckn:buyerAttributes"] + if !ok { + return "" + } + buyerAttrsMap, ok := buyerAttrs.(map[string]interface{}) + if !ok { + return "" + } + if utilityId, ok := buyerAttrsMap["utilityId"]; ok { + if s, ok := utilityId.(string); ok { + return s + } + } + return "" +} + +// extractSellerUtilityID extracts the seller's utilityId (discom ID) from orderItemAttributes.providerAttributes. +// Path: orderItemAttributes -> providerAttributes -> utilityId +func extractSellerUtilityID(orderItemAttrs map[string]interface{}) string { + if orderItemAttrs == nil { + return "" + } + providerAttrs, ok := orderItemAttrs["providerAttributes"] + if !ok { + return "" + } + providerAttrsMap, ok := providerAttrs.(map[string]interface{}) + if !ok { + return "" + } + if utilityId, ok := providerAttrsMap["utilityId"]; ok { + if s, ok := utilityId.(string); ok { + return s + } + } + return "" +} + +// extractTimeWindowField extracts a time field from the offer attributes' deliveryWindow. +// Path: offerAttributes -> deliveryWindow -> schema:startTime / schema:endTime +func extractTimeWindowField(offerAttrs map[string]interface{}, field string) string { + if offerAttrs == nil { + return "" + } + + // Navigate to deliveryWindow + deliveryWindow, ok := offerAttrs["deliveryWindow"] + if !ok { + return "" + } + + dwMap, ok := deliveryWindow.(map[string]interface{}) + if !ok { + return "" + } + + if v, ok := dwMap[field]; ok { + if s, ok := v.(string); ok { + return s + } + } + return "" +} + +// mapTradeDetails creates trade details from an order item. +func mapTradeDetails(item OrderItem) []TradeDetail { + tradeUnit := normalizeTradeUnit(item.Quantity.UnitText) + + return []TradeDetail{ + { + TradeQty: item.Quantity.UnitQuantity, + TradeType: "ENERGY", // Default to ENERGY for P2P trading + TradeUnit: tradeUnit, + }, + } +} + +// normalizeTradeUnit converts unit text to ledger API enum format. +func normalizeTradeUnit(unitText string) string { + normalized := strings.ToUpper(strings.TrimSpace(unitText)) + switch normalized { + case "KWH", "KW": + return normalized + case "KW/H", "KILOWATT-HOUR", "KILOWATT HOUR": + return "KWH" + case "KILOWATT": + return "KW" + default: + // Default to KWH for energy trading + return "KWH" + } +} + +// generateClientReference creates an idempotency key from transaction and order item IDs. +func generateClientReference(transactionID, orderItemID string) string { + return fmt.Sprintf("onix-%s-%s", transactionID, orderItemID) +} + +// ExtractAction extracts the action from the request URL path or body. +func ExtractAction(urlPath string, body []byte) string { + // First, try to extract from URL path + // Expected format: /bap/receiver/{action} or /bpp/caller/{action} + parts := strings.Split(strings.Trim(urlPath, "/"), "/") + if len(parts) >= 3 { + return parts[len(parts)-1] + } + + // Fallback: extract from body context + var payload struct { + Context struct { + Action string `json:"action"` + } `json:"context"` + } + if err := json.Unmarshal(body, &payload); err == nil && payload.Context.Action != "" { + return payload.Context.Action + } + + return "" +} + +// ------------------------- +// on_status parsing and mapping +// ------------------------- + +// ParseOnStatus parses the raw JSON body into an OnStatusPayload. +func ParseOnStatus(body []byte) (*OnStatusPayload, error) { + var payload OnStatusPayload + if err := json.Unmarshal(body, &payload); err != nil { + return nil, fmt.Errorf("failed to parse on_status payload: %w", err) + } + return &payload, nil +} + +// MapToLedgerRecordRequests converts an on_status payload to ledger RECORD requests. +// Returns one LedgerRecordRequest per order item with aggregated meter readings. +// role should be BUYER_DISCOM or SELLER_DISCOM. +func MapToLedgerRecordRequests(payload *OnStatusPayload, role string) []LedgerRecordRequest { + records := make([]LedgerRecordRequest, 0, len(payload.Message.Order.OrderItems)) + + isBuyerDiscom := role == "BUYER_DISCOM" + + for _, item := range payload.Message.Order.OrderItems { + // Extract meter readings from fulfillmentAttributes + meterReadings := extractMeterReadings(item.OrderItemAttributes) + if len(meterReadings) == 0 { + continue // Skip items without meter readings + } + + // Aggregate allocatedEnergy from all meter readings + totalAllocatedEnergy := 0.0 + for _, reading := range meterReadings { + totalAllocatedEnergy += reading.AllocatedEnergy + } + + // Create validation metric based on role + // BUYER_DISCOM → ACTUAL_PULLED + // SELLER_DISCOM → ACTUAL_PUSHED + var metricType string + if isBuyerDiscom { + metricType = "ACTUAL_PULLED" + } else { + metricType = "ACTUAL_PUSHED" + } + + metric := ValidationMetric{ + ValidationMetricType: metricType, + ValidationMetricValue: totalAllocatedEnergy, + } + + record := LedgerRecordRequest{ + Role: role, + TransactionID: payload.Context.TransactionID, + OrderItemID: item.AcceptedOffer.ID, + ClientReference: generateClientReference(payload.Context.TransactionID, item.AcceptedOffer.ID), + } + + // Assign metrics based on role + if isBuyerDiscom { + record.BuyerFulfillmentValidationMetrics = []ValidationMetric{metric} + } else { + record.SellerFulfillmentValidationMetrics = []ValidationMetric{metric} + } + + records = append(records, record) + } + + return records +} + +// extractMeterReadings extracts meter readings from orderItemAttributes.fulfillmentAttributes.meterReadings +func extractMeterReadings(orderItemAttrs map[string]interface{}) []MeterReading { + if orderItemAttrs == nil { + return nil + } + + // Navigate: orderItemAttributes → fulfillmentAttributes → meterReadings + fulfillmentAttrs, ok := orderItemAttrs["fulfillmentAttributes"] + if !ok { + return nil + } + + fulfillmentMap, ok := fulfillmentAttrs.(map[string]interface{}) + if !ok { + return nil + } + + meterReadingsRaw, ok := fulfillmentMap["meterReadings"] + if !ok { + return nil + } + + meterReadingsSlice, ok := meterReadingsRaw.([]interface{}) + if !ok { + return nil + } + + readings := make([]MeterReading, 0, len(meterReadingsSlice)) + for _, readingRaw := range meterReadingsSlice { + readingMap, ok := readingRaw.(map[string]interface{}) + if !ok { + continue + } + + reading := MeterReading{ + ConsumedEnergy: extractFloat(readingMap, "consumedEnergy"), + ProducedEnergy: extractFloat(readingMap, "producedEnergy"), + AllocatedEnergy: extractFloat(readingMap, "allocatedEnergy"), + Unit: extractStringField(readingMap, "unit"), + } + + if tw, ok := readingMap["beckn:timeWindow"]; ok { + if twMap, ok := tw.(map[string]interface{}); ok { + reading.TimeWindow = twMap + } + } + + readings = append(readings, reading) + } + + return readings +} + +// extractFloat extracts a float64 from a map, handling both float64 and int types. +func extractFloat(m map[string]interface{}, key string) float64 { + if m == nil { + return 0 + } + if v, ok := m[key]; ok { + switch val := v.(type) { + case float64: + return val + case int: + return float64(val) + case int64: + return float64(val) + } + } + return 0 +} diff --git a/plugins/degledgerrecorder/mapper_test.go b/plugins/degledgerrecorder/mapper_test.go new file mode 100644 index 00000000..f2a3d7e8 --- /dev/null +++ b/plugins/degledgerrecorder/mapper_test.go @@ -0,0 +1,594 @@ +package degledgerrecorder + +import ( + "encoding/json" + "testing" +) + +// Sample on_confirm payload for testing +const sampleOnConfirmPayload = `{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "timestamp": "2024-10-04T10:25:05Z", + "message_id": "msg-on-confirm-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "ttl": "PT30S", + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + "message": { + "order": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Order", + "beckn:id": "order-energy-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001", + "beckn:buyer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Buyer", + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/98765456", + "utilityCustomerId": "BESCOM-CUST-001", + "utilityId": "BESCOM-KA" + } + }, + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOrder", + "bap_id": "bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "total_quantity": { + "unitQuantity": 25.0, + "unitText": "kWh" + } + }, + "beckn:orderItems": [ + { + "beckn:orderedItem": "energy-resource-solar-001", + "beckn:quantity": { + "unitQuantity": 15.0, + "unitText": "kWh" + }, + "beckn:orderItemAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyOrderItem", + "providerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyCustomer", + "meterId": "der://meter/100200300", + "utilityCustomerId": "TPDDL-CUST-001", + "utilityId": "TPDDL-DL" + } + }, + "beckn:acceptedOffer": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "@type": "beckn:Offer", + "beckn:id": "offer-morning-001", + "beckn:descriptor": { + "@type": "beckn:Descriptor", + "schema:name": "Morning Solar Energy Offer" + }, + "beckn:provider": "provider-solar-farm-001", + "beckn:items": ["energy-resource-solar-001"], + "beckn:price": { + "@type": "schema:PriceSpecification", + "schema:price": 0.15, + "schema:priceCurrency": "USD", + "unitText": "kWh", + "applicableQuantity": { + "unitQuantity": 20.0, + "unitText": "kWh" + } + }, + "beckn:offerAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld", + "@type": "EnergyTradeOffer", + "pricingModel": "PER_KWH", + "deliveryWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z" + }, + "validityWindow": { + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T00:00:00Z", + "schema:endTime": "2026-01-09T05:00:00Z" + } + } + } + } + ] + } + } +}` + +func TestExtractBuyerID(t *testing.T) { + tests := []struct { + name string + buyer map[string]interface{} + expected string + }{ + { + name: "nil buyer", + buyer: nil, + expected: "", + }, + { + name: "empty buyer", + buyer: map[string]interface{}{}, + expected: "", + }, + { + name: "buyer without buyerAttributes", + buyer: map[string]interface{}{ + "beckn:id": "buyer-001", + }, + expected: "", + }, + { + name: "buyer with buyerAttributes containing meterId", + buyer: map[string]interface{}{ + "beckn:id": "buyer-001", + "beckn:buyerAttributes": map[string]interface{}{ + "meterId": "der://meter/98765456", + "utilityId": "BESCOM-KA", + }, + }, + expected: "der://meter/98765456", + }, + { + name: "buyer with buyerAttributes but no meterId", + buyer: map[string]interface{}{ + "beckn:id": "buyer-001", + "beckn:buyerAttributes": map[string]interface{}{ + "utilityId": "BESCOM-KA", + }, + }, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractBuyerID(tt.buyer) + if result != tt.expected { + t.Errorf("extractBuyerID() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestExtractSellerID(t *testing.T) { + tests := []struct { + name string + orderItemAttrs map[string]interface{} + expected string + }{ + { + name: "nil orderItemAttrs", + orderItemAttrs: nil, + expected: "", + }, + { + name: "empty orderItemAttrs", + orderItemAttrs: map[string]interface{}{}, + expected: "", + }, + { + name: "orderItemAttrs without providerAttributes", + orderItemAttrs: map[string]interface{}{ + "@type": "EnergyOrderItem", + }, + expected: "", + }, + { + name: "orderItemAttrs with providerAttributes containing meterId", + orderItemAttrs: map[string]interface{}{ + "@type": "EnergyOrderItem", + "providerAttributes": map[string]interface{}{ + "meterId": "der://meter/100200300", + "utilityId": "TPDDL-DL", + }, + }, + expected: "der://meter/100200300", + }, + { + name: "orderItemAttrs with providerAttributes but no meterId", + orderItemAttrs: map[string]interface{}{ + "@type": "EnergyOrderItem", + "providerAttributes": map[string]interface{}{ + "utilityId": "TPDDL-DL", + }, + }, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractSellerID(tt.orderItemAttrs) + if result != tt.expected { + t.Errorf("extractSellerID() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestExtractBuyerUtilityID(t *testing.T) { + tests := []struct { + name string + buyer map[string]interface{} + expected string + }{ + { + name: "nil buyer", + buyer: nil, + expected: "", + }, + { + name: "buyer with buyerAttributes containing utilityId", + buyer: map[string]interface{}{ + "beckn:id": "buyer-001", + "beckn:buyerAttributes": map[string]interface{}{ + "meterId": "der://meter/98765456", + "utilityId": "BESCOM-KA", + }, + }, + expected: "BESCOM-KA", + }, + { + name: "buyer with buyerAttributes but no utilityId", + buyer: map[string]interface{}{ + "beckn:id": "buyer-001", + "beckn:buyerAttributes": map[string]interface{}{ + "meterId": "der://meter/98765456", + }, + }, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractBuyerUtilityID(tt.buyer) + if result != tt.expected { + t.Errorf("extractBuyerUtilityID() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestExtractSellerUtilityID(t *testing.T) { + tests := []struct { + name string + orderItemAttrs map[string]interface{} + expected string + }{ + { + name: "nil orderItemAttrs", + orderItemAttrs: nil, + expected: "", + }, + { + name: "orderItemAttrs with providerAttributes containing utilityId", + orderItemAttrs: map[string]interface{}{ + "@type": "EnergyOrderItem", + "providerAttributes": map[string]interface{}{ + "meterId": "der://meter/100200300", + "utilityId": "TPDDL-DL", + }, + }, + expected: "TPDDL-DL", + }, + { + name: "orderItemAttrs with providerAttributes but no utilityId", + orderItemAttrs: map[string]interface{}{ + "@type": "EnergyOrderItem", + "providerAttributes": map[string]interface{}{ + "meterId": "der://meter/100200300", + }, + }, + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractSellerUtilityID(tt.orderItemAttrs) + if result != tt.expected { + t.Errorf("extractSellerUtilityID() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestMapToLedgerRecords(t *testing.T) { + // Parse the sample payload + payload, err := ParseOnConfirm([]byte(sampleOnConfirmPayload)) + if err != nil { + t.Fatalf("Failed to parse sample payload: %v", err) + } + + // Map to ledger records + records := MapToLedgerRecords(payload, "BUYER") + + // Verify we got one record (one order item in the sample) + if len(records) != 1 { + t.Fatalf("Expected 1 record, got %d", len(records)) + } + + record := records[0] + + // Test all extracted fields + tests := []struct { + field string + got string + expected string + }{ + {"Role", record.Role, "BUYER"}, + {"TransactionID", record.TransactionID, "txn-energy-001"}, + {"OrderItemID", record.OrderItemID, "offer-morning-001"}, + {"PlatformIDBuyer", record.PlatformIDBuyer, "bap.energy-consumer.com"}, + {"PlatformIDSeller", record.PlatformIDSeller, "bpp.energy-provider.com"}, + {"BuyerID", record.BuyerID, "der://meter/98765456"}, + {"SellerID", record.SellerID, "der://meter/100200300"}, + {"DiscomIDBuyer", record.DiscomIDBuyer, "BESCOM-KA"}, + {"DiscomIDSeller", record.DiscomIDSeller, "TPDDL-DL"}, + {"TradeTime", record.TradeTime, "2024-10-04T10:25:05Z"}, + {"DeliveryStartTime", record.DeliveryStartTime, "2026-01-09T06:00:00Z"}, + {"DeliveryEndTime", record.DeliveryEndTime, "2026-01-09T12:00:00Z"}, + } + + for _, tt := range tests { + t.Run(tt.field, func(t *testing.T) { + if tt.got != tt.expected { + t.Errorf("%s = %q, want %q", tt.field, tt.got, tt.expected) + } + }) + } + + // Verify trade details + if len(record.TradeDetails) != 1 { + t.Fatalf("Expected 1 trade detail, got %d", len(record.TradeDetails)) + } + + tradeDetail := record.TradeDetails[0] + if tradeDetail.TradeQty != 15.0 { + t.Errorf("TradeQty = %f, want %f", tradeDetail.TradeQty, 15.0) + } + if tradeDetail.TradeType != "ENERGY" { + t.Errorf("TradeType = %q, want %q", tradeDetail.TradeType, "ENERGY") + } + if tradeDetail.TradeUnit != "KWH" { + t.Errorf("TradeUnit = %q, want %q", tradeDetail.TradeUnit, "KWH") + } + + // Verify client reference format + expectedClientRef := "onix-txn-energy-001-offer-morning-001" + if record.ClientReference != expectedClientRef { + t.Errorf("ClientReference = %q, want %q", record.ClientReference, expectedClientRef) + } +} + +func TestMapToLedgerRecords_MultipleOrderItems(t *testing.T) { + // Create a payload with multiple order items + payloadWithMultipleItems := `{ + "context": { + "version": "2.0.0", + "action": "on_confirm", + "timestamp": "2024-10-04T10:25:05Z", + "message_id": "msg-001", + "transaction_id": "txn-multi-001", + "bap_id": "bap.test.com", + "bap_uri": "https://bap.test.com", + "bpp_id": "bpp.test.com", + "bpp_uri": "https://bpp.test.com", + "ttl": "PT30S", + "domain": "deg:p2p-trading" + }, + "message": { + "order": { + "beckn:id": "order-001", + "beckn:orderStatus": "CREATED", + "beckn:seller": "seller-001", + "beckn:buyer": { + "beckn:id": "buyer-001", + "beckn:buyerAttributes": { + "meterId": "der://meter/buyer-meter", + "utilityId": "BUYER-DISCOM" + } + }, + "beckn:orderAttributes": {}, + "beckn:orderItems": [ + { + "beckn:orderedItem": "item-001", + "beckn:quantity": {"unitQuantity": 10.0, "unitText": "kWh"}, + "beckn:orderItemAttributes": { + "providerAttributes": { + "meterId": "der://meter/seller-meter-1", + "utilityId": "SELLER-DISCOM-1" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-001", + "beckn:offerAttributes": {} + } + }, + { + "beckn:orderedItem": "item-002", + "beckn:quantity": {"unitQuantity": 20.0, "unitText": "kWh"}, + "beckn:orderItemAttributes": { + "providerAttributes": { + "meterId": "der://meter/seller-meter-2", + "utilityId": "SELLER-DISCOM-2" + } + }, + "beckn:acceptedOffer": { + "beckn:id": "offer-002", + "beckn:offerAttributes": {} + } + } + ] + } + } + }` + + payload, err := ParseOnConfirm([]byte(payloadWithMultipleItems)) + if err != nil { + t.Fatalf("Failed to parse payload: %v", err) + } + + records := MapToLedgerRecords(payload, "SELLER") + + if len(records) != 2 { + t.Fatalf("Expected 2 records, got %d", len(records)) + } + + // First order item + if records[0].SellerID != "der://meter/seller-meter-1" { + t.Errorf("Record[0].SellerID = %q, want %q", records[0].SellerID, "der://meter/seller-meter-1") + } + if records[0].DiscomIDSeller != "SELLER-DISCOM-1" { + t.Errorf("Record[0].DiscomIDSeller = %q, want %q", records[0].DiscomIDSeller, "SELLER-DISCOM-1") + } + if records[0].TradeDetails[0].TradeQty != 10.0 { + t.Errorf("Record[0].TradeQty = %f, want %f", records[0].TradeDetails[0].TradeQty, 10.0) + } + + // Second order item + if records[1].SellerID != "der://meter/seller-meter-2" { + t.Errorf("Record[1].SellerID = %q, want %q", records[1].SellerID, "der://meter/seller-meter-2") + } + if records[1].DiscomIDSeller != "SELLER-DISCOM-2" { + t.Errorf("Record[1].DiscomIDSeller = %q, want %q", records[1].DiscomIDSeller, "SELLER-DISCOM-2") + } + if records[1].TradeDetails[0].TradeQty != 20.0 { + t.Errorf("Record[1].TradeQty = %f, want %f", records[1].TradeDetails[0].TradeQty, 20.0) + } + + // Both should have the same buyer info + for i, rec := range records { + if rec.BuyerID != "der://meter/buyer-meter" { + t.Errorf("Record[%d].BuyerID = %q, want %q", i, rec.BuyerID, "der://meter/buyer-meter") + } + if rec.DiscomIDBuyer != "BUYER-DISCOM" { + t.Errorf("Record[%d].DiscomIDBuyer = %q, want %q", i, rec.DiscomIDBuyer, "BUYER-DISCOM") + } + } +} + +func TestExtractTimeWindowField(t *testing.T) { + tests := []struct { + name string + offerAttrs map[string]interface{} + field string + expected string + }{ + { + name: "nil offerAttrs", + offerAttrs: nil, + field: "schema:startTime", + expected: "", + }, + { + name: "empty offerAttrs", + offerAttrs: map[string]interface{}{}, + field: "schema:startTime", + expected: "", + }, + { + name: "offerAttrs without deliveryWindow", + offerAttrs: map[string]interface{}{ + "pricingModel": "PER_KWH", + }, + field: "schema:startTime", + expected: "", + }, + { + name: "offerAttrs with deliveryWindow containing startTime", + offerAttrs: map[string]interface{}{ + "pricingModel": "PER_KWH", + "deliveryWindow": map[string]interface{}{ + "@type": "beckn:TimePeriod", + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z", + }, + }, + field: "schema:startTime", + expected: "2026-01-09T06:00:00Z", + }, + { + name: "offerAttrs with deliveryWindow containing endTime", + offerAttrs: map[string]interface{}{ + "deliveryWindow": map[string]interface{}{ + "schema:startTime": "2026-01-09T06:00:00Z", + "schema:endTime": "2026-01-09T12:00:00Z", + }, + }, + field: "schema:endTime", + expected: "2026-01-09T12:00:00Z", + }, + { + name: "offerAttrs with deliveryWindow but missing requested field", + offerAttrs: map[string]interface{}{ + "deliveryWindow": map[string]interface{}{ + "schema:startTime": "2026-01-09T06:00:00Z", + }, + }, + field: "schema:endTime", + expected: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := extractTimeWindowField(tt.offerAttrs, tt.field) + if result != tt.expected { + t.Errorf("extractTimeWindowField() = %q, want %q", result, tt.expected) + } + }) + } +} + +func TestParseOnConfirm(t *testing.T) { + payload, err := ParseOnConfirm([]byte(sampleOnConfirmPayload)) + if err != nil { + t.Fatalf("ParseOnConfirm failed: %v", err) + } + + // Verify context parsing + if payload.Context.Action != "on_confirm" { + t.Errorf("Context.Action = %q, want %q", payload.Context.Action, "on_confirm") + } + if payload.Context.TransactionID != "txn-energy-001" { + t.Errorf("Context.TransactionID = %q, want %q", payload.Context.TransactionID, "txn-energy-001") + } + + // Verify order parsing + if payload.Message.Order.ID != "order-energy-001" { + t.Errorf("Order.ID = %q, want %q", payload.Message.Order.ID, "order-energy-001") + } + if len(payload.Message.Order.OrderItems) != 1 { + t.Errorf("len(OrderItems) = %d, want %d", len(payload.Message.Order.OrderItems), 1) + } +} + +func TestParseOnConfirm_InvalidJSON(t *testing.T) { + _, err := ParseOnConfirm([]byte("invalid json")) + if err == nil { + t.Error("Expected error for invalid JSON, got nil") + } +} + +// Helper to pretty print JSON for debugging +func prettyJSON(v interface{}) string { + b, _ := json.MarshalIndent(v, "", " ") + return string(b) +} diff --git a/plugins/degledgerrecorder/recorder.go b/plugins/degledgerrecorder/recorder.go new file mode 100644 index 00000000..8bc63200 --- /dev/null +++ b/plugins/degledgerrecorder/recorder.go @@ -0,0 +1,270 @@ +package degledgerrecorder + +import ( + "context" + "fmt" + "strings" + "sync" + + "github.com/beckn-one/beckn-onix/pkg/log" + "github.com/beckn-one/beckn-onix/pkg/model" +) + +// DEGLedgerRecorder is a Step plugin that records trade data to the DEG Ledger +// after on_confirm calls. +type DEGLedgerRecorder struct { + config *Config + client *LedgerClient + + // wg tracks in-flight async requests for graceful shutdown + wg sync.WaitGroup +} + +// New creates a new DEGLedgerRecorder instance. +func New(cfg map[string]string) (*DEGLedgerRecorder, error) { + config, err := ParseConfig(cfg) + if err != nil { + return nil, err + } + + // Create Beckn signer if signing is configured + var signer *BecknSigner + if config.SigningPrivateKey != "" && config.SubscriberID != "" && config.UniqueKeyID != "" { + signer, err = NewBecknSigner( + config.SubscriberID, + config.UniqueKeyID, + config.SigningPrivateKey, + config.SignatureValiditySeconds, + ) + if err != nil { + return nil, fmt.Errorf("failed to create Beckn signer: %w", err) + } + + // Log signing configuration source + configSource := "explicit config" + if config.SigningFromEnv { + configSource = "environment variables (Vault/K8s secrets compatible)" + } + fmt.Printf("[DEGLedgerRecorder] Beckn signing enabled (subscriber_id=%s, key_id=%s, source=%s)\n", + config.SubscriberID, config.UniqueKeyID, configSource) + } else if config.APIKey != "" { + fmt.Printf("[DEGLedgerRecorder] Simple API key authentication enabled\n") + } else { + fmt.Printf("[DEGLedgerRecorder] WARNING: No authentication configured for ledger API calls\n") + } + + // Log enabled actions and role + fmt.Printf("[DEGLedgerRecorder] Enabled actions: [%s], role: %s\n", + strings.Join(config.Actions, ", "), config.Role) + + client := NewLedgerClient( + config.LedgerHost, + config.AsyncTimeout, + config.RetryCount, + config.APIKey, + config.AuthHeader, + config.DebugLogging, + signer, + ) + + return &DEGLedgerRecorder{ + config: config, + client: client, + }, nil +} + +// Run implements the Step interface. It processes the request and records +// events to the DEG Ledger based on configured actions. +func (r *DEGLedgerRecorder) Run(ctx *model.StepContext) error { + // Skip if plugin is disabled + if !r.config.Enabled { + log.Debug(ctx, "DEGLedgerRecorder: plugin disabled, skipping") + return nil + } + + // Extract the action from the request + action := ExtractAction(ctx.Request.URL.Path, ctx.Body) + + // Check if this action is enabled + if !r.config.IsActionEnabled(action) { + log.Debugf(ctx, "DEGLedgerRecorder: action '%s' not in configured actions %v, skipping", action, r.config.Actions) + return nil + } + + // Route to the appropriate handler based on action + switch action { + case ActionOnConfirm: + return r.handleOnConfirm(ctx) + case ActionOnStatus: + return r.handleOnStatus(ctx) + default: + log.Debugf(ctx, "DEGLedgerRecorder: no handler for action '%s', skipping", action) + return nil + } +} + +// handleOnConfirm processes on_confirm events and sends to /ledger/put. +func (r *DEGLedgerRecorder) handleOnConfirm(ctx *model.StepContext) error { + log.Infof(ctx, "DEGLedgerRecorder: processing on_confirm") + + // DEBUG: Log the raw body received + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: raw body length=%d", len(ctx.Body)) + if len(ctx.Body) < 5000 { + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: raw body:\n%s", string(ctx.Body)) + } else { + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: raw body (truncated):\n%s...", string(ctx.Body[:5000])) + } + + // Parse the on_confirm payload + payload, err := ParseOnConfirm(ctx.Body) + if err != nil { + log.Warnf(ctx, "DEGLedgerRecorder: failed to parse on_confirm payload: %v", err) + return nil + } + + // DEBUG: Log parsed payload details + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: parsed context - transaction_id=%s, action=%s, bap_id=%s, bpp_id=%s", + payload.Context.TransactionID, payload.Context.Action, payload.Context.BapID, payload.Context.BppID) + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: order items count=%d", len(payload.Message.Order.OrderItems)) + + // Map to ledger records (one per order item) + records := MapToLedgerRecords(payload, r.config.Role) + + // DEBUG: Log mapped records + for i, rec := range records { + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: record[%d] - transactionId=%s, orderItemId=%s, platformIdBuyer=%s, platformIdSeller=%s", + i, rec.TransactionID, rec.OrderItemID, rec.PlatformIDBuyer, rec.PlatformIDSeller) + } + + if len(records) == 0 { + log.Warnf(ctx, "DEGLedgerRecorder: no order items found in on_confirm, skipping ledger recording") + return nil + } + + log.Infof(ctx, "DEGLedgerRecorder: mapped %d ledger records from on_confirm (transaction_id=%s)", + len(records), payload.Context.TransactionID) + + // Send records to ledger asynchronously (fire-and-forget) + r.sendPutRecordsAsync(ctx, records, payload.Context.TransactionID) + + return nil +} + +// handleOnStatus processes on_status events and sends meter readings to /ledger/record. +func (r *DEGLedgerRecorder) handleOnStatus(ctx *model.StepContext) error { + log.Infof(ctx, "DEGLedgerRecorder: processing on_status") + + // Validate role - only discom roles can use /ledger/record + if !r.config.IsDiscomRole() { + log.Warnf(ctx, "DEGLedgerRecorder: on_status requires BUYER_DISCOM or SELLER_DISCOM role, got %s", r.config.Role) + return nil + } + + // DEBUG: Log the raw body received + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: raw body length=%d", len(ctx.Body)) + if len(ctx.Body) < 5000 { + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: raw body:\n%s", string(ctx.Body)) + } else { + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: raw body (truncated):\n%s...", string(ctx.Body[:5000])) + } + + // Parse the on_status payload + payload, err := ParseOnStatus(ctx.Body) + if err != nil { + log.Warnf(ctx, "DEGLedgerRecorder: failed to parse on_status payload: %v", err) + return nil + } + + // DEBUG: Log parsed payload details + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: parsed context - transaction_id=%s, action=%s", + payload.Context.TransactionID, payload.Context.Action) + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: order items count=%d", len(payload.Message.Order.OrderItems)) + + // Map to ledger record requests (one per order item with meter readings) + records := MapToLedgerRecordRequests(payload, r.config.Role) + + // DEBUG: Log mapped records + for i, rec := range records { + metricCount := len(rec.BuyerFulfillmentValidationMetrics) + len(rec.SellerFulfillmentValidationMetrics) + log.Debugf(ctx, "DEGLedgerRecorder DEBUG: record[%d] - transactionId=%s, orderItemId=%s, metrics=%d", + i, rec.TransactionID, rec.OrderItemID, metricCount) + } + + if len(records) == 0 { + log.Warnf(ctx, "DEGLedgerRecorder: no meter readings found in on_status, skipping ledger recording") + return nil + } + + log.Infof(ctx, "DEGLedgerRecorder: mapped %d ledger record requests from on_status (transaction_id=%s)", + len(records), payload.Context.TransactionID) + + // Send records to ledger asynchronously (fire-and-forget) + r.sendRecordActualsAsync(ctx, records, payload.Context.TransactionID) + + return nil +} + +// sendPutRecordsAsync sends ledger PUT records in the background without blocking the main flow. +// Used for on_confirm → /ledger/put +func (r *DEGLedgerRecorder) sendPutRecordsAsync(parentCtx *model.StepContext, records []LedgerPutRequest, transactionID string) { + for _, record := range records { + r.wg.Add(1) + go func(rec LedgerPutRequest) { + defer r.wg.Done() + + // Create a new context with timeout for the async operation + ctx, cancel := context.WithTimeout(context.Background(), r.config.AsyncTimeout) + defer cancel() + + resp, err := r.client.PutRecord(ctx, rec) + if err != nil { + log.Errorf(parentCtx, err, + "DEGLedgerRecorder: failed to PUT record to ledger (transaction_id=%s, order_item_id=%s): %v", + rec.TransactionID, rec.OrderItemID, err) + return + } + + log.Infof(parentCtx, + "DEGLedgerRecorder: successfully PUT record to ledger (transaction_id=%s, order_item_id=%s, record_id=%s)", + rec.TransactionID, rec.OrderItemID, resp.RecordID) + }(record) + } +} + +// sendRecordActualsAsync sends meter readings/validation metrics in the background. +// Used for on_status → /ledger/record +func (r *DEGLedgerRecorder) sendRecordActualsAsync(parentCtx *model.StepContext, records []LedgerRecordRequest, transactionID string) { + for _, record := range records { + r.wg.Add(1) + go func(rec LedgerRecordRequest) { + defer r.wg.Done() + + // Create a new context with timeout for the async operation + ctx, cancel := context.WithTimeout(context.Background(), r.config.AsyncTimeout) + defer cancel() + + resp, err := r.client.RecordActuals(ctx, rec) + if err != nil { + log.Errorf(parentCtx, err, + "DEGLedgerRecorder: failed to RECORD actuals to ledger (transaction_id=%s, order_item_id=%s): %v", + rec.TransactionID, rec.OrderItemID, err) + return + } + + log.Infof(parentCtx, + "DEGLedgerRecorder: successfully RECORDED actuals to ledger (transaction_id=%s, order_item_id=%s, record_id=%s)", + rec.TransactionID, rec.OrderItemID, resp.RecordID) + }(record) + } +} + +// Close gracefully shuts down the recorder, waiting for in-flight requests. +func (r *DEGLedgerRecorder) Close() { + // Wait for all in-flight requests to complete + r.wg.Wait() + + // Close the HTTP client + if r.client != nil { + r.client.Close() + } +} diff --git a/plugins/degledgerrecorder/signer.go b/plugins/degledgerrecorder/signer.go new file mode 100644 index 00000000..af99864f --- /dev/null +++ b/plugins/degledgerrecorder/signer.go @@ -0,0 +1,120 @@ +package degledgerrecorder + +import ( + "crypto/ed25519" + "encoding/base64" + "errors" + "fmt" + "time" + + "golang.org/x/crypto/blake2b" +) + +// BecknSigner generates Beckn-compliant Authorization headers using ed25519 signing. +type BecknSigner struct { + subscriberID string + uniqueKeyID string + signingPrivateKey []byte + signatureValidity time.Duration +} + +// NewBecknSigner creates a new BecknSigner instance. +// signingPrivateKeyBase64 should be the base64-encoded ed25519 seed (32 bytes). +func NewBecknSigner(subscriberID, uniqueKeyID, signingPrivateKeyBase64 string, validitySeconds int) (*BecknSigner, error) { + if subscriberID == "" { + return nil, errors.New("subscriberID is required for signing") + } + if uniqueKeyID == "" { + return nil, errors.New("uniqueKeyID is required for signing") + } + if signingPrivateKeyBase64 == "" { + return nil, errors.New("signingPrivateKey is required for signing") + } + + privateKeyBytes, err := base64.StdEncoding.DecodeString(signingPrivateKeyBase64) + if err != nil { + return nil, fmt.Errorf("failed to decode signing private key: %w", err) + } + + if len(privateKeyBytes) != ed25519.SeedSize { + return nil, fmt.Errorf("invalid signing private key length: expected %d bytes, got %d", ed25519.SeedSize, len(privateKeyBytes)) + } + + validity := time.Duration(validitySeconds) * time.Second + if validity <= 0 { + validity = 30 * time.Second // Default 30 seconds validity + } + + return &BecknSigner{ + subscriberID: subscriberID, + uniqueKeyID: uniqueKeyID, + signingPrivateKey: privateKeyBytes, + signatureValidity: validity, + }, nil +} + +// GenerateAuthHeader generates a Beckn-compliant Authorization header for the given payload. +// Returns the header value in the format: +// Signature keyId="||ed25519",algorithm="ed25519",created="",expires="",headers="(created) (expires) digest",signature="" +func (s *BecknSigner) GenerateAuthHeader(payload []byte) (string, error) { + now := time.Now() + createdAt := now.Unix() + expiresAt := now.Add(s.signatureValidity).Unix() + + // Generate the signing string using BLAKE2b-512 + signingString, err := s.createSigningString(payload, createdAt, expiresAt) + if err != nil { + return "", fmt.Errorf("failed to create signing string: %w", err) + } + + // Sign the signing string with ed25519 + signature, err := s.sign([]byte(signingString)) + if err != nil { + return "", fmt.Errorf("failed to sign: %w", err) + } + + signatureB64 := base64.StdEncoding.EncodeToString(signature) + + // Build the Authorization header in Beckn format + // Format: Signature keyId="...",algorithm="ed25519",created="...",expires="...",headers="(created) (expires) digest",signature="..." + authHeader := fmt.Sprintf( + `Signature keyId="%s|%s|ed25519",algorithm="ed25519",created="%d",expires="%d",headers="(created) (expires) digest",signature="%s"`, + s.subscriberID, + s.uniqueKeyID, + createdAt, + expiresAt, + signatureB64, + ) + + return authHeader, nil +} + +// createSigningString creates the string to be signed using BLAKE2b-512 hash. +// Format: (created): \n(expires): \ndigest: BLAKE-512= +func (s *BecknSigner) createSigningString(payload []byte, createdAt, expiresAt int64) (string, error) { + hasher, err := blake2b.New512(nil) + if err != nil { + return "", fmt.Errorf("failed to create BLAKE2b hasher: %w", err) + } + + _, err = hasher.Write(payload) + if err != nil { + return "", fmt.Errorf("failed to hash payload: %w", err) + } + + hashSum := hasher.Sum(nil) + digestB64 := base64.StdEncoding.EncodeToString(hashSum) + + return fmt.Sprintf("(created): %d\n(expires): %d\ndigest: BLAKE-512=%s", createdAt, expiresAt, digestB64), nil +} + +// sign signs the given data using ed25519. +func (s *BecknSigner) sign(data []byte) ([]byte, error) { + privateKey := ed25519.NewKeyFromSeed(s.signingPrivateKey) + return ed25519.Sign(privateKey, data), nil +} + +// IsConfigured returns true if the signer has valid configuration. +func (s *BecknSigner) IsConfigured() bool { + return s != nil && len(s.signingPrivateKey) > 0 +} diff --git a/plugins/go.mod b/plugins/go.mod new file mode 100644 index 00000000..540cab14 --- /dev/null +++ b/plugins/go.mod @@ -0,0 +1,36 @@ +module github.com/beckn-one/deg/plugins + +go 1.24.0 + +require ( + github.com/beckn-one/beckn-onix v0.0.0 + github.com/google/uuid v1.6.0 + golang.org/x/crypto v0.36.0 +) + +replace github.com/beckn-one/beckn-onix => ../../beckn-onix + +require ( + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/go-logr/logr v1.4.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect + github.com/prometheus/client_golang v1.18.0 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.45.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/rs/zerolog v1.34.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/prometheus v0.46.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect + golang.org/x/sys v0.38.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect +) diff --git a/plugins/go.sum b/plugins/go.sum new file mode 100644 index 00000000..e880e00a --- /dev/null +++ b/plugins/go.sum @@ -0,0 +1,70 @@ +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= +github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= +github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= +github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/prometheus v0.46.0 h1:I8WIFXR351FoLJYuloU4EgXbtNX2URfU/85pUPheIEQ= +go.opentelemetry.io/otel/exporters/prometheus v0.46.0/go.mod h1:ztwVUHe5DTR/1v7PeuGRnU5Bbd4QKYwApWmuutKsJSs= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/scripts/generate_postman_collection.py b/scripts/generate_postman_collection.py index 1f37c39c..61992568 100755 --- a/scripts/generate_postman_collection.py +++ b/scripts/generate_postman_collection.py @@ -99,22 +99,47 @@ "bap_adapter_url": "http://localhost:8081/bap/caller", "bpp_adapter_url": "http://localhost:8082/bpp/caller", "examples_path": "examples/p2p-trading/v2", - # "output_path": "testnet/p2p-energy-trading-devkit/postman", + # "output_path": "testnet/p2p-trading-devkit/postman", "structure": "flat" # Flat file structure + }, + "p2p-enrollment": { + "domain": "beckn.one:deg:p2p-enrollment:2.0.0", + "bap_id": "p2p-enrollment-sandbox1.com", + "bap_uri": "http://onix-bap:8081/bap/receiver", + "bpp_id": "p2p-enrollment-sandbox2.com", + "bpp_uri": "http://onix-bpp:8082/bpp/receiver", + "bap_adapter_url": "http://localhost:8081/bap/caller", + "bpp_adapter_url": "http://localhost:8082/bpp/caller", + "examples_path": "examples/enrollment/v2", + # "output_path": "testnet/p2p-enrollment-devkit/postman", + "structure": "flat" # Flat file structure (like p2p-trading) + }, + "p2p-trading-interdiscom": { + "domain": "beckn.one:deg:p2p-trading-interdiscom:2.0.0", + "bap_id": "p2p-trading-sandbox1.com", + "bap_uri": "http://onix-bap:8081/bap/receiver", + "bpp_id": "p2p-trading-sandbox2.com", + "bpp_uri": "http://onix-bpp:8082/bpp/receiver", + "bap_adapter_url": "http://localhost:8081/bap/caller", + "bpp_adapter_url": "http://localhost:8082/bpp/caller", + "examples_path": "examples/p2p-trading-interdiscom/v2", + # "output_path": "testnet/p2p-trading-interdiscom-devkit/postman", + "structure": "flat" # Flat file structure (like p2p-trading) } } # Role-based file name filters (regex patterns) ROLE_FILTERS = { "BAP": [ - r".*-request\.json$", # P2P trading: *-request.json + r".*-request.*\.json$", # P2P trading/enrollment: *-request*.json (includes suffixes like -otp, -oauth2) r"^\d+_(discover|select|init|confirm|status|update|track|rating|support|cancel)\.json$", # EV charging: numbered folders r"^(discover|select|init|confirm|status|update|track|rating|support|cancel).*\.json$" # General pattern ], "BPP": [ - r".*-response\.json$", # P2P trading: *-response.json + r"^(?!cascaded-).*-response.*\.json$", # P2P trading/enrollment: *-response*.json (excludes cascaded-) r"^\d+_on_(discover|select|init|confirm|update|track|status|rating|support|cancel).*\.json$", # EV charging: on_* folders - r"^on_(discover|select|init|confirm|update|track|status|rating|support|cancel).*\.json$" # General pattern + r"^on[-_](discover|select|init|confirm|update|track|status|rating|support|cancel).*\.json$", # General pattern (on- or on_) + r"^publish-.*\.json$" # BPP-initiated publish action to CDS ], "UtilityBPP": [ r"^cascaded-.*\.json$" # Cascaded requests/responses @@ -135,6 +160,11 @@ "cancel": "cancel", } +# BPP-initiated actions (not callbacks, but BPP initiating requests to CDS, etc.) +BPP_INITIATED_ACTIONS = { + "publish": "publish", +} + # BPP response actions BPP_ACTIONS = { "on_discover": "on_discover", @@ -185,47 +215,63 @@ def extract_action_from_filename(filename: str, role: str) -> Optional[str]: "discover-request.json" (BAP) -> "discover" "discover-response.json" (BPP) -> "on_discover" "cascaded-init-request.json" (UtilityBPP) -> "init" + "init-request-otp.json" (BAP) -> "init" + "on-init-response-oauth2.json" (BPP) -> "on_init" """ # Remove .json extension name = filename.replace('.json', '') - # Handle P2P trading flat structure - strict role-based matching + # Handle P2P trading/enrollment flat structure - strict role-based matching if role == "BAP": - # BAP only matches *-request.json (not *-response.json) - if name.endswith('-request'): - action = name.replace('-request', '') - if action in BAP_ACTIONS: - return action - # Also handle cascaded requests for BAP (though typically UtilityBPP) - if name.startswith('cascaded-') and name.endswith('-request'): - action = name.replace('cascaded-', '').replace('-request', '') - if action in BAP_ACTIONS: - return action + # BAP only matches *-request*.json (not *-response*.json) + # Pattern: action-request or action-request-suffix + if '-request' in name and '-response' not in name: + # Extract action from before -request + match = re.match(r'^(cascaded-)?([a-z]+)-request', name, re.IGNORECASE) + if match: + is_cascaded = match.group(1) is not None + action = match.group(2) + if action in BAP_ACTIONS: + return action elif role == "BPP": - # BPP only matches *-response.json (not *-request.json) - if name.endswith('-response'): - # For responses, the action in filename is the request action - # We need to convert to BPP action (e.g., "discover" -> "on_discover") - request_action = name.replace('-response', '') - # Check if it's a direct BPP action - if request_action in BPP_ACTIONS: - return request_action - # Convert request action to response action - if request_action in BAP_ACTIONS: - return f"on_{request_action}" - # Handle cascaded responses - if name.startswith('cascaded-') and name.endswith('-response'): - request_action = name.replace('cascaded-', '').replace('-response', '') - if request_action in BAP_ACTIONS: - return f"on_{request_action}" + # BPP matches *-response*.json (not *-request*.json) AND publish-*.json + # Patterns: action-response, on-action-response, action-response-suffix, publish-* + + # First check for BPP-initiated actions (like publish-catalog.json) + if name.startswith('publish-'): + match = re.match(r'^(publish)-', name, re.IGNORECASE) + if match: + action = match.group(1).lower() + if action in BPP_INITIATED_ACTIONS: + return action + + if '-response' in name and '-request' not in name: + # First try: on-action-response pattern (e.g., on-init-response-oauth2) + match = re.match(r'^(cascaded-)?(on[-_])?([a-z]+)-response', name, re.IGNORECASE) + if match: + is_cascaded = match.group(1) is not None + has_on_prefix = match.group(2) is not None + action = match.group(3) + + if has_on_prefix: + # Already has on_ prefix (e.g., on-init-response -> on_init) + bpp_action = f"on_{action}" + if bpp_action in BPP_ACTIONS: + return bpp_action + else: + # No on_ prefix, convert to BPP action (e.g., discover-response -> on_discover) + if action in BAP_ACTIONS: + return f"on_{action}" elif role == "UtilityBPP": - # UtilityBPP matches cascaded-*-request.json - if name.startswith('cascaded-') and name.endswith('-request'): - action = name.replace('cascaded-', '').replace('-request', '') - if action in BAP_ACTIONS: - return action + # UtilityBPP matches cascaded-*-request*.json + if name.startswith('cascaded-') and '-request' in name: + match = re.match(r'^cascaded-([a-z]+)-request', name, re.IGNORECASE) + if match: + action = match.group(1) + if action in BAP_ACTIONS: + return action return None @@ -527,7 +573,8 @@ def generate_collection( action_mapping = BAP_ACTIONS adapter_url_var = "bap_adapter_url" elif role == "BPP": - action_mapping = BPP_ACTIONS + # BPP uses both callback actions and BPP-initiated actions (like publish to CDS) + action_mapping = {**BPP_ACTIONS, **BPP_INITIATED_ACTIONS} adapter_url_var = "bpp_adapter_url" elif role == "UtilityBPP": action_mapping = BAP_ACTIONS # UtilityBPP uses BAP actions @@ -587,16 +634,14 @@ def generate_collection( ) action_items.append(request) - # Create folder even if empty (for actions with no examples yet, like status) - folder = { - "name": action, - "item": action_items - } - collection_items.append(folder) + # Only create folder if it has requests if action_items: + folder = { + "name": action, + "item": action_items + } + collection_items.append(folder) print(f" Created folder '{action}' with {len(action_items)} request(s)") - else: - print(f" Created empty folder '{action}' (no examples found)") # Build collection collection = { @@ -639,9 +684,9 @@ def main(): parser.add_argument( "--devkit", type=str, - choices=["ev-charging", "p2p-trading"], + choices=["ev-charging", "p2p-trading", "p2p-enrollment", "p2p-trading-interdiscom"], required=True, - help="Devkit type: 'ev-charging' or 'p2p-trading'" + help="Devkit type: 'ev-charging', 'p2p-trading', 'p2p-enrollment', or 'p2p-trading-interdiscom'" ) parser.add_argument( "--role", diff --git a/scripts/validate_schema.py b/scripts/validate_schema.py index 5807b214..28eaf628 100644 --- a/scripts/validate_schema.py +++ b/scripts/validate_schema.py @@ -244,24 +244,81 @@ def load_schema_for_context_url(context_url, attribute_schemas_map, registry_lis return None -def _validate_attribute_object(data, schema_def, schema_type, schema_name, path, errors, registry_list): +def _validate_attribute_object(data, schema_def, schema_type, schema_name, path, errors, registry_list, schema_url=None): """ Validate a domain-specific attribute object against its schema. - Modifies the schema to allow @context and @type properties even when - additionalProperties is False, as these are required for JSON-LD. + Uses $ref to full document to allow nested $ref resolution, then handles + @context and @type properties which are required for JSON-LD. Args: data: Object data to validate - schema_def: Schema definition from attributes.yaml + schema_def: Schema definition from attributes.yaml (used as fallback) schema_type: Type name for logging (e.g., "ChargingOffer") schema_name: Schema name for logging (e.g., "EvChargingOffer") path: JSON path for error reporting errors: List to append validation errors to registry_list: Registry list for reference resolution + schema_url: Full URL to the attributes.yaml file (for $ref resolution) """ print(f" Validating {schema_type} (from {schema_name}) at {path or 'root'}...") + # Try using $ref to full document first (allows nested $ref resolution) + if schema_url: + try: + # Get the full document resource from registry + full_doc_resource = registry_list[0].get(schema_url) + if full_doc_resource: + full_doc = full_doc_resource.contents + # Extract the schema from the full document + if "components" in full_doc and "schemas" in full_doc["components"]: + target_schema = full_doc["components"]["schemas"].get(schema_type) + if target_schema: + # Recursively convert relative $ref to absolute $ref + # Also need to handle nested schemas referenced within this schema + def convert_relative_refs(obj, base_url, full_doc_schemas=None): + """Recursively convert relative $ref to absolute $ref""" + if isinstance(obj, dict): + result = {} + for k, v in obj.items(): + if k == "$ref" and isinstance(v, str) and v.startswith("#"): + # Convert relative ref to absolute + result[k] = f"{base_url}{v}" + elif k == "allOf" and isinstance(v, list): + # Handle allOf with $ref - convert $ref in allOf items + result[k] = [convert_relative_refs(item, base_url, full_doc_schemas) for item in v] + else: + result[k] = convert_relative_refs(v, base_url, full_doc_schemas) + return result + elif isinstance(obj, list): + return [convert_relative_refs(item, base_url, full_doc_schemas) for item in obj] + return obj + + # Get schema and convert relative $ref to absolute $ref + resolved_schema = copy.deepcopy(target_schema) + resolved_schema = convert_relative_refs(resolved_schema, schema_url) + + # Modify to allow @context and @type (required for JSON-LD) + if resolved_schema.get("additionalProperties") is False: + if "properties" not in resolved_schema: + resolved_schema["properties"] = {} + resolved_schema["properties"]["@context"] = {"type": "string"} + resolved_schema["properties"]["@type"] = {"type": "string"} + + # Validate against the resolved and modified schema + validate(instance=data, schema=resolved_schema, registry=registry_list[0]) + print(f" {schema_type} at {path or 'root'} is VALID.") + return + except ValidationError as e: + print(f" {schema_type} at {path or 'root'} is INVALID: {e.message}") + print(f" Path: {e.json_path}") + errors.append(f"{path} ({schema_type}): {e.message}") + return + except Exception as e: + # Fallback to direct validation if $ref resolution fails + pass + + # Fallback: direct validation with schema fragment (may fail on nested $ref) validation_schema = copy.deepcopy(schema_def) if validation_schema.get("additionalProperties") is False: if "properties" not in validation_schema: @@ -378,12 +435,12 @@ def find_and_validate_objects(data, path=""): # Try exact match first if schema_type in schemas: - _validate_attribute_object(data, schemas[schema_type], schema_type, schema_name, path, errors, registry_list) + _validate_attribute_object(data, schemas[schema_type], schema_type, schema_name, path, errors, registry_list, schema_url) else: # Try case-insensitive match for schema_key, schema_def in schemas.items(): if schema_key.lower() == schema_type.lower(): - _validate_attribute_object(data, schema_def, schema_key, schema_name, path, errors, registry_list) + _validate_attribute_object(data, schema_def, schema_key, schema_name, path, errors, registry_list, schema_url) break # Recursively check children diff --git a/specification/energy-credentials/examples/consumption-profile-vc.json b/specification/energy-credentials/examples/consumption-profile-vc.json new file mode 100644 index 00000000..34c6c0c2 --- /dev/null +++ b/specification/energy-credentials/examples/consumption-profile-vc.json @@ -0,0 +1,25 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org/", + "https://nfh-trust-labs.github.io/vc-schemas/energy-credentials/consumption-profile-vc/context.jsonld" + ], + "id": "urn:uuid:b2c3d4e5-6789-01ab-cdef-234567890123", + "type": ["VerifiableCredential", "ConsumptionProfileCredential"], + "issuer": { + "id": "did:web:bescom.karnataka.gov.in", + "name": "BESCOM - Bangalore Electricity Supply Company", + "licenseNumber": "KERC/DL/BESCOM/2024" + }, + "issuanceDate": "2025-01-15T10:30:00Z", + "credentialSubject": { + "id": "did:example:consumer:priya123", + "consumerNumber": "BESCOM-2025-MR4-567890", + "fullName": "Priya Sharma", + "premisesType": "Residential", + "connectionType": "Single-phase", + "sanctionedLoadKW": 5, + "tariffCategoryCode": "LT-2a", + "meterNumber": "BESCOM-SM-2025-789456" + } + } diff --git a/specification/energy-credentials/examples/generation-profile-vc.json b/specification/energy-credentials/examples/generation-profile-vc.json new file mode 100644 index 00000000..a84e1ff1 --- /dev/null +++ b/specification/energy-credentials/examples/generation-profile-vc.json @@ -0,0 +1,28 @@ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org/", + "https://nfh-trust-labs.github.io/vc-schemas/energy-credentials/generation-profile-vc/context.jsonld" + ], + "id": "urn:uuid:c3d4e5f6-7890-12ab-cdef-345678901234", + "type": ["VerifiableCredential", "GenerationProfileCredential"], + "issuer": { + "id": "did:web:bescom.karnataka.gov.in", + "name": "BESCOM - Bangalore Electricity Supply Company", + "licenseNumber": "KERC/DL/BESCOM/2024" + }, + "issuanceDate": "2025-01-15T10:30:00Z", + "credentialSubject": { + "id": "did:example:consumer:priya123", + "consumerNumber": "BESCOM-2025-MR4-567890", + "fullName": "Priya Sharma", + "meterNumber": "BESCOM-SM-2025-789456", + "assetId": "SRTPV-KA-BLR-2025-001234", + "generationType": "Solar", + "capacityKW": 3, + "commissioningDate": "2025-01-10", + "manufacturer": "Tata Power Solar", + "modelNumber": "TP300-Series" + } + } + diff --git a/specification/energy-credentials/examples/program-enrollment-vc.json b/specification/energy-credentials/examples/program-enrollment-vc.json new file mode 100644 index 00000000..d9608304 --- /dev/null +++ b/specification/energy-credentials/examples/program-enrollment-vc.json @@ -0,0 +1,23 @@ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org/", + "https://nfh-trust-labs.github.io/vc-schemas/energy-credentials/program-enrollment-vc/context.jsonld" + ], + "id": "urn:uuid:7f8e9d0c-5678-1234-abcd-123456789abc", + "type": ["VerifiableCredential", "UtilityProgramEnrollmentCredential"], + "issuer": { + "id": "did:web:bescom.karnataka.gov.in", + "name": "BESCOM - Bangalore Electricity Supply Company", + "licenseNumber": "KERC/DL/BESCOM/2024" + }, + "issuanceDate": "2025-01-15T11:00:00Z", + "credentialSubject": { + "id": "did:example:consumer:priya123", + "consumerNumber": "BESCOM-2025-MR4-567890", + "fullName": "Priya Sharma", + "programName": "BESCOM Surya Raitha - Rooftop Solar Net Metering", + "programCode": "SRTPV-NM-2025", + "enrollmentDate": "2025-01-15" + } + } diff --git a/specification/energy-credentials/examples/storage-profile-vc.json b/specification/energy-credentials/examples/storage-profile-vc.json new file mode 100644 index 00000000..3e54592e --- /dev/null +++ b/specification/energy-credentials/examples/storage-profile-vc.json @@ -0,0 +1,26 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org/", + "https://nfh-trust-labs.github.io/vc-schemas/energy-credentials/storage-profile-vc/context.jsonld" + ], + "id": "urn:uuid:d4e5f6a7-8901-23ab-cdef-456789012345", + "type": ["VerifiableCredential", "StorageProfileCredential"], + "issuer": { + "id": "did:web:bescom.karnataka.gov.in", + "name": "BESCOM - Bangalore Electricity Supply Company", + "licenseNumber": "KERC/DL/BESCOM/2024" + }, + "issuanceDate": "2025-01-15T10:30:00Z", + "credentialSubject": { + "id": "did:example:consumer:priya123", + "consumerNumber": "BESCOM-2025-MR4-567890", + "fullName": "Priya Sharma", + "meterNumber": "BESCOM-SM-2025-789456", + "assetId": "BESS-KA-BLR-2025-000456", + "storageCapacityKWh": 10, + "powerRatingKW": 5, + "commissioningDate": "2025-01-12", + "storageType": "LithiumIon" + } + } diff --git a/specification/energy-credentials/examples/utility-customer-vc. json b/specification/energy-credentials/examples/utility-customer-vc. json new file mode 100644 index 00000000..16bd0e9f --- /dev/null +++ b/specification/energy-credentials/examples/utility-customer-vc. json @@ -0,0 +1,31 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://schema.org/", + "https://nfh-trust-labs.github.io/vc-schemas/energy-credentials/utility-customer-vc/context.jsonld" + ], + "id": "urn:uuid:a1b2c3d4-5678-90ab-cdef-123456789012", + "type": ["VerifiableCredential", "UtilityCustomerCredential"], + "issuer": { + "id": "did:web:bescom.karnataka.gov.in", + "name": "BESCOM - Bangalore Electricity Supply Company", + "licenseNumber": "KERC/DL/BESCOM/2024" + }, + "issuanceDate": "2025-01-15T10:30:00Z", + "credentialSubject": { + "id": "did:example:consumer:priya123", + "consumerNumber": "BESCOM-2025-MR4-567890", + "maskedIdNumber": "XXXX-XXXX-4523", + "fullName": "Priya Sharma", + "installationAddress": { + "fullAddress": "42, 3rd Cross, Indiranagar", + "city": "Bengaluru", + "district": "Bengaluru Urban", + "stateProvince": "Karnataka", + "postalCode": "560038", + "country": "IN" + }, + "meterNumber": "BESCOM-SM-2025-789456", + "serviceConnectionDate": "2020-03-15" + } + } diff --git a/specification/schema/EnergyEnrollment/v0.2/README.md b/specification/schema/EnergyEnrollment/v0.2/README.md new file mode 100644 index 00000000..61484045 --- /dev/null +++ b/specification/schema/EnergyEnrollment/v0.2/README.md @@ -0,0 +1,283 @@ +# EnergyEnrollment Schema (v0.2) + +## Introduction + +The **EnergyEnrollment** schema composes with the core Beckn `Fulfillment` and `Order` entities to support program enrollment flows for Digital Energy Programs (VPPs, demand response, P2P trading, etc.). This schema enables credential-based enrollment where the BPP verifies provided credentials, checks for conflicts, and issues enrollment credentials without needing to perform initial eligibility or ownership checks. + +### Use Cases + +- **Program Enrollment**: Enables users to enroll in digital energy programs (VPPs, demand response, P2P trading, community solar, special tariffs) +- **Credential Verification**: Supports verification of meter ownership, program eligibility, and DER certification credentials +- **Conflict Detection**: Identifies conflicts with existing enrollments (overlapping dates, duplicate meter/DER enrollments) +- **Enrollment Management**: Tracks enrollment lifecycle from initiation through confirmation, active status, and unenrollment +- **Consent Management**: Supports consent credential issuance and revocation for data collection and DER control +- **Audit Trail**: Maintains enrollment logs and references for compliance and record-keeping + +### Key Features + +- **Credential-Based**: Uses W3C Verifiable Credentials (v2.0) for proof of ownership, eligibility, and enrollment +- **Narrow BPP Role**: BPP verifies credentials and checks conflicts; initial checks handled by calling entity (Portal/BAP) +- **Conflict Prevention**: Detects overlapping enrollments and program conflicts before confirmation +- **Type Coercion**: Context includes type coercion rules for shorter, cleaner examples +- **Status List Integration**: Supports W3C VC Status Lists for credential revocation (consent and enrollment) +- **Lifecycle Management**: Tracks enrollment from pending through active, cancelled, or suspended states +- **Multi-Asset Support**: Handles enrollments with multiple meters and DERs + +## Schema Composition Points + +This schema composes with: +- `core/v2/attributes.yaml#Fulfillment.fulfillmentAttributes` - For credentials and existing enrollments in `init` requests +- `core/v2/attributes.yaml#Order.orderAttributes` - For enrollment details, verification results, and enrollment credentials in responses + +## Context and Type Coercion + +The schema provides a context file (`context.jsonld`) that includes type coercion rules, enabling shorter examples by automatically inferring `@type` values from property names: + +- `fulfillments` array → `beckn:Fulfillment` +- `items` array → `beckn:Item` +- `provider` property → `beckn:Provider` +- `customer` property → `beckn:Customer` +- `instrument` property → `beckn:Instrument` +- `meters` array → `beckn:Meter` +- `ders` array → `beckn:DER` +- `credentials` array → `VerifiableCredential` +- `credentialVerification` property → `CredentialVerification` +- `conflictCheck` property → `ConflictCheck` +- And more... + +Explicit `@type` declarations are still supported and work correctly with type coercion enabled. + +## Attributes + +### Used in `fulfillmentAttributes` (init request) + +| Attribute | Type | Required | Description | Use Case | +|-----------|------|----------|-------------|----------| +| `credentials` | array<VerifiableCredential> | No | Array of W3C Verifiable Credentials provided by calling entity | Contains meter ownership, program eligibility, and DER certification credentials. BPP verifies these credentials without needing to check with utilities or evaluate eligibility criteria. | +| `existingEnrollments` | array<VerifiableCredential> | No | Array of existing enrollment credentials for conflict checking | Provided by calling entity to help BPP identify conflicts. Contains existing ProgramEnrollmentCredential VCs showing current enrollments. | + +### Used in `orderAttributes` (on_init response) + +| Attribute | Type | Required | Description | Use Case | +|-----------|------|----------|-------------|----------| +| `credentialVerification` | CredentialVerification | No | Results of credential verification performed by BPP | Returned after BPP verifies provided credentials. Contains overall status and list of verified credentials with verification timestamps. | +| `credentialVerification.status` | enum | No | Overall verification status: VERIFIED, FAILED, PARTIAL | Indicates if all, some, or no credentials were successfully verified. | +| `credentialVerification.verifiedCredentials` | array<VerifiedCredential> | No | Array of credentials that were successfully verified | Details of each verified credential including credentialId, status, and verifiedAt timestamp. | +| `conflictCheck` | ConflictCheck | No | Results of conflict checking with existing enrollments | Returned after BPP checks for conflicts. Indicates if conflicts exist and provides details of conflicting enrollments. | +| `conflictCheck.hasConflict` | boolean | No | Boolean indicating if a conflict exists | True if meter/DER is already enrolled in another program with overlapping dates, false otherwise. | +| `conflictCheck.conflictingEnrollments` | array<ConflictingEnrollment> | No | Array of conflicting enrollments (only when hasConflict is true) | Details of each conflict including enrollmentId, programId, conflictReason, and conflictType. | +| `conflictCheck.checkedAt` | date-time | No | Timestamp when conflict check was performed (ISO 8601 UTC) | Used for audit trail and tracking when the check occurred. | +| `conflictCheck.message` | string | No | Human-readable message explaining conflict check results | Provides user-friendly explanation of the conflict check outcome. | + +### Used in `orderAttributes` (confirm request) + +| Attribute | Type | Required | Description | Use Case | +|-----------|------|----------|-------------|----------| +| `startDate` | date-time | No | Date and time when enrollment becomes active (ISO 8601 UTC) | Specified by calling entity. Enrollment becomes active at this time. May be in the future for scheduled enrollments. | +| `endDate` | date-time | No | Date and time when enrollment expires or ends (ISO 8601 UTC) | Specified by calling entity. Enrollment expires at this time. Used for time-limited program enrollments. | + +### Used in `orderAttributes` (on_confirm response) + +| Attribute | Type | Required | Description | Use Case | +|-----------|------|----------|-------------|----------| +| `enrollmentId` | string | No | Unique identifier for the enrollment assigned by BPP | Used for tracking, audit, enrollment management, and referencing in unenrollment requests. | +| `status` | enum | No | Enrollment status: ACTIVE, PENDING, CANCELLED, SUSPENDED | Current lifecycle state of the enrollment. ACTIVE when active, PENDING when awaiting activation, CANCELLED when unenrolled, SUSPENDED when temporarily suspended. | +| `programId` | string | No | Identifier of the digital energy program | Matches the program ID from the init request. Identifies which program the user is enrolled in. | +| `startDate` | date-time | No | Date and time when enrollment becomes active (ISO 8601 UTC) | Echoed from confirm request. When the enrollment period begins. | +| `endDate` | date-time | No | Date and time when enrollment expires or ends (ISO 8601 UTC) | Echoed from confirm request. When the enrollment period ends. | +| `enrolledAt` | date-time | No | Timestamp when enrollment was confirmed and logged by BPP (ISO 8601 UTC) | When the enrollment was actually processed. May differ from startDate if enrollment is scheduled for future activation. | +| `credential` | VerifiableCredential | No | Signed enrollment credential issued by BPP | W3C Verifiable Credential (v2.0) proving enrollment. Contains credentialId, type (ProgramEnrollmentCredential), format, credentialData (JWT or JSON-LD), credentialUrl, verificationUrl, issuedAt, and expiresAt. | +| `loggedAt` | date-time | No | Timestamp when enrollment was logged in BPP's audit system (ISO 8601 UTC) | Used for audit trail and compliance. May be same as enrolledAt or slightly later. | +| `logReference` | string | No | Reference identifier for the enrollment log entry | Used for audit trail, record keeping, and log retrieval. Enables tracking and retrieval of enrollment records. | + +### Used in `orderAttributes` (update request/response - consent revocation) + +| Attribute | Type | Required | Description | Use Case | +|-----------|------|----------|-------------|----------| +| `updateType` | enum | No | Type of update: CONSENT_REVOCATION, UNENROLLMENT | Indicates what type of update is being performed. Used to route the request to appropriate handling logic. | +| `consentRevocation` | ConsentRevocation | No | Consent revocation details | Used in update request to revoke a consent credential, and in on_update response to confirm revocation with status list information. | +| `consentRevocation.consentCredentialId` | uri | No | Identifier of the consent credential being revoked | References the Verifiable Credential ID of the consent being revoked. | +| `consentRevocation.consentType` | enum | No | Type of consent: DATA_COLLECTION, DER_CONTROL, CROSS_UTILITY_SHARING | Identifies which type of consent is being revoked. DATA_COLLECTION for data sharing, DER_CONTROL for device control, CROSS_UTILITY_SHARING for cross-utility data sharing. | +| `consentRevocation.reason` | string | No | Reason for revocation | Values: USER_REQUESTED, PROGRAM_TERMINATED, COMPLIANCE_REQUIREMENT, etc. | +| `consentRevocation.revokedAt` | date-time | No | Timestamp when consent was revoked (ISO 8601 UTC) | In request, when user initiated revocation. In response, when BPP processed it. | +| `consentRevocation.effectiveDate` | date-time | No | Date and time when revocation becomes effective (ISO 8601 UTC) | May be in the future for scheduled revocations. | +| `consentRevocation.status` | enum | No | Revocation status: REVOKED, PENDING (only in response) | REVOKED when processed, PENDING when scheduled for future. Only present in on_update response. | +| `consentRevocation.statusListUrl` | uri | No | URL of W3C VC status list (only in response) | URL where the revoked credential's status is recorded. Used for verification. Only present in on_update response after revocation is processed. | +| `consentRevocation.statusListIndex` | string | No | Index in status list (only in response) | Index in the status list where this credential's revocation status is recorded. Only present in on_update response. | +| `consentRevocation.message` | string | No | Human-readable message about revocation status (only in response) | Provides user-friendly explanation of the revocation outcome. Only present in on_update response. | + +### Used in `orderAttributes` (update request/response - unenrollment) + +| Attribute | Type | Required | Description | Use Case | +|-----------|------|----------|-------------|----------| +| `unenrollment` | Unenrollment | No | Unenrollment details | Used in update request to cancel enrollment, and in on_update response to confirm cancellation with status list information. | +| `unenrollment.enrollmentId` | string | No | Identifier of the enrollment being cancelled | References the enrollment to be cancelled. Must match an active enrollment. | +| `unenrollment.reason` | string | No | Reason for unenrollment | Values: USER_REQUESTED, PROGRAM_TERMINATED, COMPLIANCE_REQUIREMENT, etc. | +| `unenrollment.effectiveDate` | date-time | No | Date and time when unenrollment becomes effective (ISO 8601 UTC) | May be in the future for scheduled unenrollment. | +| `unenrollment.revokeAllConsents` | boolean | No | Whether all associated consents should be revoked | If true, all consent credentials associated with this enrollment will be revoked during unenrollment. | +| `unenrollment.status` | enum | No | Unenrollment status: CANCELLED, PENDING (only in response) | CANCELLED when processed, PENDING when scheduled for future. Only present in on_update response. | +| `unenrollment.cancelledAt` | date-time | No | Timestamp when enrollment was cancelled (ISO 8601 UTC) (only in response) | When the BPP processed the unenrollment. Only present in on_update response. | +| `unenrollment.enrollmentCredentialStatus` | object | No | Status information for enrollment credential after revocation (only in response) | Contains statusListUrl, statusListIndex, and revoked flag. Only present in on_update response. | +| `unenrollment.consentsRevoked` | array | No | Array of consent credentials revoked during unenrollment (only in response) | Details of each revoked consent credential including consentCredentialId, statusListUrl, statusListIndex, and revoked flag. Only present when revokeAllConsents was true. | +| `unenrollment.message` | string | No | Human-readable message about unenrollment status (only in response) | Provides user-friendly explanation of the unenrollment outcome. Only present in on_update response. | + +## VerifiableCredential Structure + +The schema uses W3C Verifiable Credentials Data Model v2.0 (`https://www.w3.org/TR/vc-data-model-2.0/`). Each credential object contains: + +| Attribute | Type | Required | Description | +|-----------|------|----------|-------------| +| `credentialId` | string | Yes | Unique identifier for the credential | +| `type` | enum | Yes | Credential type: MeterOwnershipCredential, ProgramEligibilityCredential, DERCertificationCredential, ProgramEnrollmentCredential | +| `format` | enum | Yes | Credential format: VC-JWT, VC-JSON-LD | +| `credentialData` | string | Yes | The credential data itself (JWT or JSON-LD string) | +| `credentialUrl` | uri | No | URL where the credential can be accessed | +| `verificationUrl` | uri | No | URL for verifying the credential | +| `issuedAt` | date-time | No | Timestamp when credential was issued (maps to W3C VC issuanceDate) | +| `expiresAt` | date-time | No | Timestamp when credential expires (maps to W3C VC expirationDate) | +| `derId` | string | No | DER identifier (only for DERCertificationCredential) | + +## Example Usage + +### Init Request (fulfillmentAttributes) + +```json +{ + "beckn:fulfillmentAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credentials": [ + { + "credentialId": "vc-meter-ownership-001", + "type": "MeterOwnershipCredential", + "format": "VC-JWT", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", + "verificationUrl": "https://utility-example-001.com/verify/vc-meter-ownership-001" + } + ], + "existingEnrollments": [ + { + "credentialId": "vc:enrollment:existing-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." + } + ] + } +} +``` + +### On_Init Response (orderAttributes) + +```json +{ + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "credentialVerification": { + "status": "VERIFIED", + "verifiedCredentials": [ + { + "credentialId": "vc-meter-ownership-001", + "status": "VERIFIED", + "verifiedAt": "2024-10-15T10:30:05Z" + } + ] + }, + "conflictCheck": { + "hasConflict": false, + "checkedAt": "2024-10-15T10:30:05Z", + "message": "No conflicts found with existing enrollments" + } + } +} +``` + +### On_Confirm Response (orderAttributes) + +```json +{ + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "enrollmentId": "enrollment-consumer-001", + "status": "ACTIVE", + "programId": "program-flex-demand-response-001", + "startDate": "2024-11-01T00:00:00Z", + "endDate": "2025-10-31T23:59:59Z", + "enrolledAt": "2024-10-15T10:35:05Z", + "credential": { + "credentialId": "vc:enrollment:consumer-001", + "type": "ProgramEnrollmentCredential", + "format": "VC-JWT", + "credentialUrl": "https://vpp-program-owner.example.com/credentials/vc:enrollment:consumer-001", + "verificationUrl": "https://vpp-program-owner.example.com/verify/vc:enrollment:consumer-001", + "issuedAt": "2024-10-15T10:35:05Z", + "credentialData": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." + }, + "loggedAt": "2024-10-15T10:35:05Z", + "logReference": "log-enrollment-consumer-001" + } +} +``` + +### Update Request - Consent Revocation (orderAttributes) + +```json +{ + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "updateType": "CONSENT_REVOCATION", + "consentRevocation": { + "consentCredentialId": "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001", + "consentType": "DATA_COLLECTION", + "reason": "USER_REQUESTED", + "revokedAt": "2024-11-20T14:30:00Z", + "effectiveDate": "2024-11-20T14:30:00Z" + } + } +} +``` + +### Update Request - Unenrollment (orderAttributes) + +```json +{ + "beckn:orderAttributes": { + "@context": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld", + "@type": "EnergyEnrollment", + "updateType": "UNENROLLMENT", + "unenrollment": { + "enrollmentId": "enrollment-consumer-001", + "reason": "USER_REQUESTED", + "effectiveDate": "2024-11-20T15:00:00Z", + "revokeAllConsents": true + } + } +} +``` + +## Design Principles + +1. **Narrow BPP Role**: BPP only verifies credentials and checks conflicts; initial eligibility and ownership checks are handled by calling entity +2. **Credential-Based**: Uses W3C Verifiable Credentials v2.0 for all proofs and enrollments +3. **Frugal Schema**: Only essential nouns added; reuses existing Beckn structures where possible +4. **Proper Slotting**: Uses standard Beckn slotting (`fulfillmentAttributes`, `orderAttributes`) +5. **Type Coercion**: Context includes type coercion for shorter, cleaner examples +6. **Status List Integration**: Supports W3C VC Status Lists for verifiable credential revocation +7. **Lifecycle Management**: Tracks enrollment from initiation through active status to unenrollment + +## Schema Files + +- **context.jsonld**: JSON-LD context with type coercion rules +- **vocab.jsonld**: Vocabulary definitions for all EnergyEnrollment terms +- **attributes.yaml**: OpenAPI 3.1.1 schema for grammar and semantics validation + +## Related Schemas + +- **Core v2**: Base Beckn protocol schemas (`Fulfillment`, `Order`) +- **W3C VC v2.0**: Verifiable Credentials Data Model (`https://www.w3.org/TR/vc-data-model-2.0/`) +- **EnergyResource**: For energy source characteristics in discovery +- **EnergyProsumer**: For prosumer attributes including meters, DERs, credentials, source information, and certification + diff --git a/specification/schema/EnergyEnrollment/v0.2/attributes.yaml b/specification/schema/EnergyEnrollment/v0.2/attributes.yaml new file mode 100644 index 00000000..d3fc73bd --- /dev/null +++ b/specification/schema/EnergyEnrollment/v0.2/attributes.yaml @@ -0,0 +1,980 @@ +openapi: 3.1.1 +info: + title: Energy Enrollment — Enrollment Attributes (v0.2) + version: 0.2.0 + x-profile-id: profiles/energy-onboarding/energy_enrollment/v0.2/enrollment + description: > + Attribute schemas for program enrollment (Fulfillment.fulfillmentAttributes and Order.orderAttributes). + These attributes support the onboarding flow where BPP verifies credentials, checks for conflicts, + and issues enrollment credentials. Used in init requests (fulfillmentAttributes) and init/confirm + responses (orderAttributes). + +components: + schemas: + ######################################################################## + # FULFILLMENT.ATTRIBUTES & ORDER.ATTRIBUTES — EnergyEnrollment + ######################################################################## + EnergyEnrollment: + type: object + additionalProperties: true + x-jsonld: + "@context": ./context.jsonld + "@type": EnergyEnrollment + description: > + Main schema for enrollment attributes. Used in: + - fulfillmentAttributes (init request): Contains credentials and existingEnrollments + - orderAttributes (on_init response): Contains credentialVerification and conflictCheck + - orderAttributes (confirm request): Contains startDate and endDate + - orderAttributes (on_confirm response): Contains full enrollment details including credential + properties: + + # Used in orderAttributes for user authentication + userAuth: + description: > + User authentication for enrollment verification. + Supports OTP-based or OAuth2/OIDC token-based authentication. + + For REQUESTS (init, confirm): + Use UserAuthRequest (OtpAuthRequest or OAuth2AuthRequest) + - OTP: Send mobile (init) or mobile+nguid+otp (confirm) + - OAuth2/OIDC: Send accessToken (and idToken for OIDC) + + For RESPONSES (on_init, on_confirm): + Use UserAuthResponse (OtpAuthResponse or OAuth2AuthResponse) + - Returns verification status, extracted identity, and session tokens + oneOf: + - $ref: '#/components/schemas/UserAuthRequest' + - $ref: '#/components/schemas/UserAuthResponse' + x-jsonld: { "@id": userAuth } + + # Used in orderAttributes (confirm request) - meters to enroll + meters: + type: array + description: > + Array of meter identifiers to enroll in the program. + Required in confirm request - order will only be confirmed if at least one meter is specified. + Each meter should include the meter ID (UMID) and optionally utility information. + If userAuth is verified but meters array is empty, on_confirm returns error "no meter specified". + items: + $ref: '#/components/schemas/MeterEnrollment' + x-jsonld: { "@id": meters, "@container": "@set" } + + # Used in fulfillmentAttributes (init request) + credentials: + type: array + description: > + Array of W3C Verifiable Credentials (https://www.w3.org/TR/vc-data-model-2.0/) provided by calling entity (Portal/BAP). + Includes meter ownership, program eligibility, and DER certification credentials. + items: + $ref: '#/components/schemas/VerifiableCredential' + x-jsonld: { "@id": credentials } + + existingEnrollments: + type: array + description: > + Array of existing W3C Verifiable Credentials for conflict checking. + Provided by calling entity to help BPP identify conflicts. + items: + $ref: '#/components/schemas/VerifiableCredential' + x-jsonld: { "@id": existingEnrollments } + + # Used in orderAttributes (on_init response) + credentialVerification: + type: object + description: > + Results of credential verification performed by BPP. + Returned in on_init response after BPP verifies provided credentials. + x-jsonld: + "@id": credentialVerification + "@type": CredentialVerification + properties: + status: + type: string + enum: [VERIFIED, FAILED, PARTIAL] + description: Overall verification status. VERIFIED if all credentials verified, FAILED if any failed, PARTIAL if some verified. + example: "VERIFIED" + x-jsonld: { "@id": status } + verifiedCredentials: + type: array + description: Array of credentials that were successfully verified. + items: + $ref: '#/components/schemas/VerifiedCredential' + x-jsonld: { "@id": verifiedCredentials } + + conflictCheck: + type: object + description: > + Results of conflict checking with existing enrollments. + Returned in on_init response after BPP checks for conflicts. + x-jsonld: + "@id": conflictCheck + "@type": ConflictCheck + properties: + hasConflict: + type: boolean + description: > + Boolean indicating if a conflict exists. True if meter/DER is already enrolled + in another program with overlapping dates, false otherwise. + example: false + x-jsonld: { "@id": hasConflict } + conflictingEnrollments: + type: array + description: > + Array of conflicting enrollments. Only present when hasConflict is true. + Empty array if no conflicts found. + items: + $ref: '#/components/schemas/ConflictingEnrollment' + x-jsonld: { "@id": conflictingEnrollments } + checkedAt: + type: string + format: date-time + description: Timestamp when conflict check was performed (ISO 8601 UTC). + example: "2024-10-15T10:30:05Z" + x-jsonld: { "@id": checkedAt } + message: + type: string + description: Human-readable message explaining conflict check results. + example: "No conflicts found with existing enrollments" + x-jsonld: { "@id": message } + + requiredCredentials: + type: array + description: > + Array of credential types that are required for enrollment. + Returned in on_init response to inform BAP what credentials are needed. + Each entry includes type, description, and status (PROVIDED, MISSING). + items: + type: object + additionalProperties: true + description: Required credential object with type, description, and status + x-jsonld: { "@id": requiredCredentials } + + requiredConsents: + type: array + description: > + Array of consent types that are required for enrollment. + Returned in on_init response to inform BAP what consents are needed. + Each entry includes type, description, and whether it's required or optional. + items: + type: object + additionalProperties: true + description: Required consent object with type, description, and required flag + x-jsonld: { "@id": requiredConsents } + + # Used in orderAttributes (confirm request) + startDate: + type: string + format: date-time + description: > + Date and time when enrollment becomes active (ISO 8601 UTC). + Specified by calling entity in confirm request, returned in on_confirm response. + example: "2024-11-01T00:00:00Z" + x-jsonld: { "@id": startDate } + + endDate: + type: string + format: date-time + description: > + Date and time when enrollment expires or ends (ISO 8601 UTC). + Specified by calling entity in confirm request, returned in on_confirm response. + example: "2025-10-31T23:59:59Z" + x-jsonld: { "@id": endDate } + + consents: + type: array + description: > + Array of consent objects provided by the buyer in confirm request. + Each consent indicates the type of consent and whether it was granted. + items: + type: object + additionalProperties: true + description: Consent object with type, granted status, grantedAt timestamp, and description + x-jsonld: { "@id": consents } + + # Used in orderAttributes (update request/response) + updateType: + type: string + enum: [CONSENT_REVOCATION, UNENROLLMENT] + description: > + Type of update being performed. CONSENT_REVOCATION for revoking consent, + UNENROLLMENT for cancelling entire enrollment. + example: "CONSENT_REVOCATION" + x-jsonld: { "@id": updateType } + + consentRevocation: + type: object + description: > + Consent revocation details. Used in update request to revoke a consent credential, + and in on_update response to confirm revocation with status list information. + x-jsonld: + "@id": consentRevocation + "@type": ConsentRevocation + properties: + consentCredentialId: + type: string + format: uri + description: > + Identifier of the consent credential being revoked. References the Verifiable Credential ID. + example: "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001" + x-jsonld: { "@id": consentCredentialId } + consentType: + type: string + enum: [DATA_COLLECTION, DER_CONTROL, CROSS_UTILITY_SHARING] + description: > + Type of consent being revoked. DATA_COLLECTION for data sharing consent, + DER_CONTROL for device control consent, CROSS_UTILITY_SHARING for cross-utility data sharing. + example: "DATA_COLLECTION" + x-jsonld: { "@id": consentType } + reason: + type: string + description: > + Reason for revocation. Values: USER_REQUESTED, PROGRAM_TERMINATED, COMPLIANCE_REQUIREMENT, etc. + example: "USER_REQUESTED" + x-jsonld: { "@id": reason } + revokedAt: + type: string + format: date-time + description: > + Timestamp when the consent was revoked (ISO 8601 UTC). + In request, this is when user initiated revocation. In response, this is when BPP processed it. + example: "2024-11-20T14:30:00Z" + x-jsonld: { "@id": revokedAt } + effectiveDate: + type: string + format: date-time + description: > + Date and time when the revocation becomes effective (ISO 8601 UTC). + May be in the future for scheduled revocations. + example: "2024-11-20T14:30:00Z" + x-jsonld: { "@id": effectiveDate } + status: + type: string + enum: [REVOKED, PENDING] + description: > + Revocation status. REVOKED when processed, PENDING when scheduled for future. + Only present in on_update response. + example: "REVOKED" + x-jsonld: { "@id": status } + statusListUrl: + type: string + format: uri + description: > + URL of the W3C VC status list where the revoked credential is recorded. + Only present in on_update response after revocation is processed. + example: "https://vpp-program-owner.example.com/status/consent-list" + x-jsonld: { "@id": statusListUrl } + statusListIndex: + type: string + description: > + Index in the status list where this credential's revocation status is recorded. + Only present in on_update response. + example: "94567" + x-jsonld: { "@id": statusListIndex } + message: + type: string + description: > + Human-readable message about the revocation status. + Only present in on_update response. + example: "Consent has been revoked and added to revocation status list." + x-jsonld: { "@id": message } + + unenrollment: + type: object + description: > + Unenrollment details. Used in update request to cancel enrollment, + and in on_update response to confirm cancellation with status list information. + x-jsonld: + "@id": unenrollment + "@type": Unenrollment + properties: + enrollmentId: + type: string + description: > + Identifier of the enrollment being cancelled. + example: "enrollment-consumer-001" + x-jsonld: { "@id": enrollmentId } + reason: + type: string + description: > + Reason for unenrollment. Values: USER_REQUESTED, PROGRAM_TERMINATED, COMPLIANCE_REQUIREMENT, etc. + example: "USER_REQUESTED" + x-jsonld: { "@id": reason } + effectiveDate: + type: string + format: date-time + description: > + Date and time when the unenrollment becomes effective (ISO 8601 UTC). + May be in the future for scheduled unenrollment. + example: "2024-11-20T15:00:00Z" + x-jsonld: { "@id": effectiveDate } + revokeAllConsents: + type: boolean + description: > + Boolean indicating whether all associated consents should be revoked during unenrollment. + If true, all consent credentials associated with this enrollment will be revoked. + example: true + x-jsonld: { "@id": revokeAllConsents } + status: + type: string + enum: [CANCELLED, PENDING] + description: > + Unenrollment status. CANCELLED when processed, PENDING when scheduled for future. + Only present in on_update response. + example: "CANCELLED" + x-jsonld: { "@id": status } + cancelledAt: + type: string + format: date-time + description: > + Timestamp when the enrollment was cancelled (ISO 8601 UTC). + Only present in on_update response. + example: "2024-11-20T15:00:05Z" + x-jsonld: { "@id": cancelledAt } + enrollmentCredentialStatus: + type: object + description: > + Status information for the enrollment credential after revocation. + Contains status list details for verification. + Only present in on_update response. + x-jsonld: { "@id": enrollmentCredentialStatus } + additionalProperties: false + properties: + statusListUrl: + type: string + format: uri + description: URL of the status list for the enrollment credential. + example: "https://vpp-program-owner.example.com/status/enrollment-list" + x-jsonld: { "@id": statusListUrl } + statusListIndex: + type: string + description: Index in the status list for the enrollment credential. + example: "12345" + x-jsonld: { "@id": statusListIndex } + revoked: + type: boolean + description: Whether the enrollment credential has been revoked. + example: true + x-jsonld: { "@id": revoked } + consentsRevoked: + type: array + description: > + Array of consent credentials that were revoked as part of unenrollment. + Only present in on_update response when revokeAllConsents was true. + items: + type: object + additionalProperties: false + properties: + consentCredentialId: + type: string + format: uri + description: Identifier of the revoked consent credential. + example: "https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001" + x-jsonld: { "@id": consentCredentialId } + statusListUrl: + type: string + format: uri + description: URL of the status list for this consent credential. + example: "https://vpp-program-owner.example.com/status/consent-list" + x-jsonld: { "@id": statusListUrl } + statusListIndex: + type: string + description: Index in the status list for this consent credential. + example: "94567" + x-jsonld: { "@id": statusListIndex } + revoked: + type: boolean + description: Whether this consent credential has been revoked. + example: true + x-jsonld: { "@id": revoked } + x-jsonld: { "@id": consentsRevoked } + message: + type: string + description: > + Human-readable message about the unenrollment status. + Only present in on_update response. + example: "Enrollment and all associated consents have been revoked." + x-jsonld: { "@id": message } + + # Used in orderAttributes (on_confirm response) + enrollmentId: + type: string + description: > + Unique identifier for the enrollment. Assigned by BPP upon enrollment confirmation. + Used for tracking, audit, and enrollment management. + example: "enrollment-consumer-001" + x-jsonld: { "@id": enrollmentId } + + programId: + type: string + description: > + Identifier of the digital energy program. Matches the program ID from the init request. + example: "program-flex-demand-response-001" + x-jsonld: { "@id": programId } + + status: + type: string + enum: [ACTIVE, PENDING, CANCELLED, SUSPENDED] + description: > + Enrollment status. ACTIVE when enrollment is active, PENDING when awaiting activation, + CANCELLED when unenrolled, SUSPENDED when temporarily suspended. + example: "ACTIVE" + x-jsonld: { "@id": status } + + enrolledAt: + type: string + format: date-time + description: > + Timestamp when enrollment was confirmed and logged by BPP (ISO 8601 UTC). + May differ from startDate if enrollment is scheduled for future activation. + example: "2024-10-15T10:35:05Z" + x-jsonld: { "@id": enrolledAt } + + credential: + type: object + description: > + Signed enrollment credential issued by BPP. Contains W3C Verifiable Credential (https://www.w3.org/TR/vc-data-model-2.0/) proving enrollment. + Returned in on_confirm response. + x-jsonld: { "@id": credential } + allOf: + - $ref: '#/components/schemas/VerifiableCredential' + + loggedAt: + type: string + format: date-time + description: > + Timestamp when enrollment was logged in BPP's audit system (ISO 8601 UTC). + Used for audit trail and compliance. + example: "2024-10-15T10:35:05Z" + x-jsonld: { "@id": loggedAt } + + logReference: + type: string + description: > + Reference identifier for the enrollment log entry. + Used for audit trail, record keeping, and log retrieval. + example: "log-enrollment-consumer-001" + x-jsonld: { "@id": logReference } + + ######################################################################## + # VerifiableCredential (W3C VC Data Model v2.0) + ######################################################################## + VerifiableCredential: + type: object + additionalProperties: false + description: > + Represents a W3C Verifiable Credential (https://www.w3.org/TR/vc-data-model-2.0/) used in enrollment flow. + This is a wrapper/reference object that contains the credential data (as JWT or JSON-LD), metadata, and URLs. + The actual credential follows W3C VC Data Model v2.0 structure. Can be a meter ownership credential, + program eligibility credential, DER certification credential, or program enrollment credential. + x-jsonld: + "@type": "vc:VerifiableCredential" + properties: + credentialId: + type: string + description: > + Unique identifier for the credential. Used to reference credentials + in verification and conflict checking. + example: "vc-meter-ownership-001" + x-jsonld: { "@id": credentialId } + + type: + type: string + enum: [MeterOwnershipCredential, ProgramEligibilityCredential, DERCertificationCredential, ProgramEnrollmentCredential] + description: > + Credential type as per W3C VC Data Model v2.0. The credential must include 'VerifiableCredential' + in its type array plus one of these specific types. MeterOwnershipCredential proves meter ownership, + ProgramEligibilityCredential proves eligibility, DERCertificationCredential + proves DER certification, ProgramEnrollmentCredential represents an enrollment. + example: "MeterOwnershipCredential" + x-jsonld: { "@id": "vc:type" } + + format: + type: string + enum: [VC-JWT, VC-JSON-LD] + description: > + Credential format as per W3C VC Data Model v2.0. VC-JWT for JWT-encoded credentials, + VC-JSON-LD for JSON-LD encoded credentials. The credentialData field contains the + encoded credential that must conform to W3C VC structure when decoded. + example: "VC-JWT" + x-jsonld: { "@id": format } + + credentialData: + type: string + description: > + The credential data itself, typically a JWT or JSON-LD string + containing the W3C Verifiable Credential (https://www.w3.org/TR/vc-data-model-2.0/). + Contains the full credential including signature/proof. When decoded, must conform + to W3C VC Data Model v2.0 structure with @context, type, credentialSubject, issuer, etc. + example: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." + x-jsonld: { "@id": credentialData } + + credentialUrl: + type: string + format: uri + description: > + URL where the credential can be accessed or retrieved. + Used for enrollment credentials returned in on_confirm response. + Optional for credentials in init request. + example: "https://vpp-program-owner.example.com/credentials/vc:enrollment:consumer-001" + x-jsonld: { "@id": credentialUrl } + + verificationUrl: + type: string + format: uri + description: > + URL for verifying the credential. Used for third-party verification + of enrollment credentials. Optional for credentials in init request. + example: "https://vpp-program-owner.example.com/verify/vc:enrollment:consumer-001" + x-jsonld: { "@id": verificationUrl } + + issuedAt: + type: string + format: date-time + description: > + Timestamp when the credential was issued (ISO 8601 UTC). + Maps to W3C VC issuanceDate property. Used for enrollment credentials in on_confirm response. + example: "2024-10-15T10:35:05Z" + x-jsonld: { "@id": "vc:issuanceDate" } + + expiresAt: + type: string + format: date-time + nullable: true + description: > + Timestamp when the credential expires (ISO 8601 UTC). + Maps to W3C VC expirationDate property. May be null for non-expiring credentials. + example: "2025-10-15T10:35:05Z" + x-jsonld: { "@id": "vc:expirationDate" } + + derId: + type: string + description: > + DER identifier associated with a DER certification credential. + Links the credential to a specific DER. Only present for + DERCertificationCredential type. + example: "der-solar-001" + x-jsonld: { "@id": derId } + + ######################################################################## + # VerifiedCredential + ######################################################################## + VerifiedCredential: + type: object + additionalProperties: false + description: > + Details of a credential that has been verified by the BPP. + Returned in credentialVerification.verifiedCredentials array. + x-jsonld: + "@type": VerifiedCredential + properties: + credentialId: + type: string + description: > + Identifier of the credential that was verified. + Matches the credentialId from the init request. + example: "vc-meter-ownership-001" + x-jsonld: { "@id": credentialId } + + status: + type: string + enum: [VERIFIED, FAILED] + description: > + Verification status for this specific credential. + VERIFIED if credential is valid, FAILED if invalid or expired. + example: "VERIFIED" + x-jsonld: { "@id": status } + + verifiedAt: + type: string + format: date-time + description: > + Timestamp when the credential was verified by BPP (ISO 8601 UTC). + example: "2024-10-15T10:30:05Z" + x-jsonld: { "@id": verifiedAt } + + ######################################################################## + # ConflictingEnrollment + ######################################################################## + ConflictingEnrollment: + type: object + additionalProperties: false + description: > + Details of a conflicting enrollment that prevents the requested + enrollment from proceeding. Returned in conflictCheck.conflictingEnrollments array. + x-jsonld: + "@type": ConflictingEnrollment + properties: + enrollmentId: + type: string + description: > + Identifier of the conflicting enrollment. + Used to reference the existing enrollment causing the conflict. + example: "enrollment-existing-001" + x-jsonld: { "@id": enrollmentId } + + programId: + type: string + description: > + Program identifier of the conflicting enrollment. + Identifies which program the meter/DER is already enrolled in. + example: "program-flex-other-001" + x-jsonld: { "@id": programId } + + conflictReason: + type: string + description: > + Human-readable description of why the conflict exists. + Explains the nature of the conflict (e.g., meter already enrolled, + overlapping dates, etc.). + example: "Meter umid-001 is already enrolled in program-flex-other-001 from 2024-09-01 to 2025-09-01" + x-jsonld: { "@id": conflictReason } + + conflictType: + type: string + enum: [METER_ALREADY_ENROLLED, DER_ALREADY_ENROLLED, PROGRAM_CONFLICT, DATE_OVERLAP] + description: > + Type of conflict. METER_ALREADY_ENROLLED if meter is enrolled, + DER_ALREADY_ENROLLED if DER is enrolled, PROGRAM_CONFLICT if program + doesn't allow multiple enrollments, DATE_OVERLAP if dates overlap. + example: "METER_ALREADY_ENROLLED" + x-jsonld: { "@id": conflictType } + + ######################################################################## + # UserAuth - REQUEST (BAP → BPP) + ######################################################################## + UserAuthRequest: + description: > + User authentication request - sent by BAP to BPP in init/confirm requests. + Supports OTP-based or OAuth2/OIDC token-based authentication. + oneOf: + - $ref: '#/components/schemas/OtpAuthRequest' + - $ref: '#/components/schemas/OAuth2AuthRequest' + discriminator: + propertyName: authMethod + mapping: + OTP: '#/components/schemas/OtpAuthRequest' + OAUTH2: '#/components/schemas/OAuth2AuthRequest' + OIDC: '#/components/schemas/OAuth2AuthRequest' + + ######################################################################## + # UserAuth - RESPONSE (BPP → BAP) + ######################################################################## + UserAuthResponse: + description: > + User authentication response - returned by BPP to BAP in on_init/on_confirm responses. + Contains verification results and extracted user identity. + oneOf: + - $ref: '#/components/schemas/OtpAuthResponse' + - $ref: '#/components/schemas/OAuth2AuthResponse' + discriminator: + propertyName: authMethod + mapping: + OTP: '#/components/schemas/OtpAuthResponse' + OAUTH2: '#/components/schemas/OAuth2AuthResponse' + OIDC: '#/components/schemas/OAuth2AuthResponse' + + ######################################################################## + # OtpAuthRequest (BAP → BPP) + ######################################################################## + OtpAuthRequest: + type: object + additionalProperties: false + required: + - authMethod + - mobile + description: > + OTP authentication request from BAP. + - Init request: Send mobile number to initiate OTP + - Confirm request: Send mobile + nguid + otp for verification + x-jsonld: + "@type": OtpAuthRequest + properties: + authMethod: + type: string + enum: [OTP] + description: Authentication method. Must be "OTP". + example: "OTP" + x-jsonld: { "@id": authMethod } + + mobile: + type: string + description: Mobile phone number in E.164 format. Required. + example: "+919999999999" + x-jsonld: { "@id": mobile } + + otp: + type: string + description: > + One-time password entered by user. + Required in confirm request (after user receives OTP via SMS). + example: "123456" + x-jsonld: { "@id": otp } + + nguid: + type: string + description: > + Session token received from on_init response. + Required in confirm request along with otp. + example: "LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm" + x-jsonld: { "@id": nguid } + + utilityCustomerId: + type: string + description: > + Customer account identifier assigned by the utility/DISCOM. + Optional - BAP may include if known from prior interactions. + example: "CUST-123456" + x-jsonld: { "@id": utilityCustomerId } + + userType: + type: string + description: > + Type of user. + CONSUMER for consumer, PRODUCER for producer, PROSUMER for prosumer. + example: "CONSUMER" + x-jsonld: { "@id": userType } + + ######################################################################## + # OtpAuthResponse (BPP → BAP) + ######################################################################## + OtpAuthResponse: + type: object + additionalProperties: false + required: + - authMethod + description: > + OTP authentication response from BPP. + - On_init response: Returns nguid and message ("OTP sent") + - On_confirm response: Returns verification result + x-jsonld: + "@type": OtpAuthResponse + properties: + authMethod: + type: string + enum: [OTP] + description: Authentication method. Always "OTP". + example: "OTP" + x-jsonld: { "@id": authMethod } + + nguid: + type: string + description: > + Session token generated by BPP. Returned in on_init response. + BAP must include this in confirm request. + example: "LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm" + x-jsonld: { "@id": nguid } + + message: + type: string + description: > + Human-readable status message. + e.g., "OTP sent to +91XXXXXX9999" or "Verification successful". + example: "OTP sent to +91XXXXXX9999. Valid for 5 minutes." + x-jsonld: { "@id": message } + + expiresAt: + type: string + format: date-time + description: When OTP/nguid expires (ISO 8601 UTC). + example: "2024-10-15T10:35:00Z" + x-jsonld: { "@id": expiresAt } + + verified: + type: boolean + description: Whether OTP verification succeeded. Present in on_confirm. + example: true + x-jsonld: { "@id": verified } + + verifiedAt: + type: string + format: date-time + description: When OTP was verified (ISO 8601 UTC). + example: "2024-10-15T10:35:05Z" + x-jsonld: { "@id": verifiedAt } + + utilityId: + type: string + description: > + Utility/DISCOM identifier returned by IdP after authentication. + Identifies which utility the authenticated user's account belongs to. + example: "utility-example-001" + x-jsonld: { "@id": utilityId } + + utilityCustomerId: + type: string + description: > + Customer account identifier assigned by the utility/DISCOM. + Returned by IdP to link the authenticated user to their utility billing account. + example: "CUST-123456" + x-jsonld: { "@id": utilityCustomerId } + + ######################################################################## + # OAuth2AuthRequest (BAP → BPP) + ######################################################################## + OAuth2AuthRequest: + type: object + additionalProperties: false + required: + - authMethod + - accessToken + description: > + OAuth2/OIDC authentication request from BAP. + Contains JWT tokens for BPP to validate. BPP extracts claims from token. + x-jsonld: + "@type": OAuth2AuthRequest + properties: + authMethod: + type: string + enum: [OAUTH2, OIDC] + description: > + Authentication method. + "OAUTH2" for access token only, "OIDC" for access + ID token. + example: "OIDC" + x-jsonld: { "@id": authMethod } + + accessToken: + type: string + description: OAuth2 access token (bearer token). Required. + example: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." + x-jsonld: { "@id": accessToken } + + idToken: + type: string + description: > + OIDC ID token (JWT with user claims). + Required when authMethod is "OIDC". + example: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." + x-jsonld: { "@id": idToken } + + refreshToken: + type: string + description: > + OAuth2 refresh token. Optional - for long-running flows + where token might expire mid-transaction. + example: "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..." + x-jsonld: { "@id": refreshToken } + + ######################################################################## + # OAuth2AuthResponse (BPP → BAP) + ######################################################################## + OAuth2AuthResponse: + type: object + additionalProperties: false + required: + - authMethod + description: > + OAuth2/OIDC authentication response from BPP. + Contains verification results and extracted user identity from token. + x-jsonld: + "@type": OAuth2AuthResponse + properties: + authMethod: + type: string + enum: [OAUTH2, OIDC] + description: Authentication method that was used. + example: "OIDC" + x-jsonld: { "@id": authMethod } + + verified: + type: boolean + description: Whether token verification succeeded. + example: true + x-jsonld: { "@id": verified } + + verifiedAt: + type: string + format: date-time + description: When token was verified (ISO 8601 UTC). + example: "2024-10-15T10:35:05Z" + x-jsonld: { "@id": verifiedAt } + + subject: + type: string + description: > + User identifier extracted from token "sub" claim. + example: "user-12345" + x-jsonld: { "@id": subject } + + issuer: + type: string + format: uri + description: > + OIDC issuer URL extracted from token "iss" claim. + example: "https://accounts.google.com" + x-jsonld: { "@id": issuer } + + scope: + type: string + description: > + Scopes granted to the token (extracted from token or introspection). + example: "openid profile email meter:read" + x-jsonld: { "@id": scope } + + expiresAt: + type: string + format: date-time + description: When the access token expires (from "exp" claim). + example: "2024-10-15T11:35:00Z" + x-jsonld: { "@id": expiresAt } + + message: + type: string + description: Human-readable verification status message. + example: "Token verified successfully" + x-jsonld: { "@id": message } + + ######################################################################## + # MeterEnrollment (Meter details for enrollment) + ######################################################################## + MeterEnrollment: + type: object + additionalProperties: false + required: + - meterId + description: > + Meter details for enrollment in an energy program. + Contains meter identifier (UMID) and optional utility information. + Used in the meters array within orderAttributes during confirm request. + At least one meter must be specified for enrollment to be confirmed. + x-jsonld: + "@type": MeterEnrollment + properties: + meterId: + type: string + description: > + Unique Meter Identifier (UMID) for the meter to be enrolled. + This is the primary identifier used by the utility/DISCOM. + example: "umid-001" + x-jsonld: { "@id": meterId } + + meterNumber: + type: string + description: > + Physical meter number as displayed on the meter device. + May differ from meterId which is the utility's internal identifier. + example: "MTR-123456" + x-jsonld: { "@id": meterNumber } + + utilityId: + type: string + description: > + Identifier of the utility/DISCOM that owns or manages the meter. + example: "utility-tpddl-001" + x-jsonld: { "@id": utilityId } + + connectionType: + type: string + enum: [residential, commercial, industrial, agricultural] + description: > + Type of electricity connection for this meter. + example: "residential" + x-jsonld: { "@id": connectionType } + + sanctionedLoad: + type: number + minimum: 0 + description: > + Sanctioned load capacity in kilowatts (kW) for this meter connection. + example: 5.0 + x-jsonld: { "@id": sanctionedLoad } + diff --git a/specification/schema/EnergyEnrollment/v0.2/context.jsonld b/specification/schema/EnergyEnrollment/v0.2/context.jsonld new file mode 100644 index 00000000..84a81147 --- /dev/null +++ b/specification/schema/EnergyEnrollment/v0.2/context.jsonld @@ -0,0 +1,126 @@ +{ + "@context": [ + "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld", + "https://www.w3.org/ns/credentials/v2", + "../vocab.jsonld", + { + "@comment": "Schema.org semantic mappings for cross-domain interoperability", + "schema": "https://schema.org/", + "owl": "http://www.w3.org/2002/07/owl#", + "fulfillments": { + "@id": "beckn:fulfillments", + "@type": "beckn:Fulfillment", + "@container": "@set" + }, + "items": { + "@id": "beckn:items", + "@type": "beckn:Item", + "@container": "@set" + }, + "provider": { + "@id": "beckn:provider", + "@type": "beckn:Provider" + }, + "descriptor": { + "@id": "beckn:descriptor", + "@type": "beckn:Descriptor" + }, + "customer": { + "@id": "beckn:customer", + "@type": "beckn:Customer" + }, + "instrument": { + "@id": "beckn:instrument", + "@type": "beckn:Instrument" + }, + "meters": { + "@id": "meters", + "@type": "MeterEnrollment", + "@container": "@set" + }, + "ders": { + "@id": "ders", + "@type": "beckn:DER", + "@container": "@set" + }, + "person": { + "@id": "beckn:person", + "@type": "schema:Person" + }, + "state": { + "@id": "beckn:state", + "@type": "beckn:State" + }, + "credentials": { + "@id": "credentials", + "@type": "VerifiableCredential", + "@container": "@set" + }, + "existingEnrollments": { + "@id": "existingEnrollments", + "@type": "VerifiableCredential", + "@container": "@set" + }, + "credentialVerification": { + "@id": "credentialVerification", + "@type": "CredentialVerification" + }, + "verifiedCredentials": { + "@id": "verifiedCredentials", + "@type": "VerifiedCredential", + "@container": "@set" + }, + "conflictCheck": { + "@id": "conflictCheck", + "@type": "ConflictCheck" + }, + "conflictingEnrollments": { + "@id": "conflictingEnrollments", + "@type": "ConflictingEnrollment", + "@container": "@set" + }, + "consentRevocation": { + "@id": "consentRevocation", + "@type": "ConsentRevocation" + }, + "unenrollment": { + "@id": "unenrollment", + "@type": "Unenrollment" + }, + "credential": { + "@id": "credential", + "@type": "VerifiableCredential" + }, + "userAuth": { + "@id": "userAuth", + "@type": "UserAuth" + }, + "UserAuth": "beckn:UserAuth", + "UserAuthRequest": "beckn:UserAuthRequest", + "UserAuthResponse": "beckn:UserAuthResponse", + "OtpAuthRequest": "beckn:OtpAuthRequest", + "OtpAuthResponse": "beckn:OtpAuthResponse", + "OAuth2AuthRequest": "beckn:OAuth2AuthRequest", + "OAuth2AuthResponse": "beckn:OAuth2AuthResponse", + "MeterEnrollment": "beckn:MeterEnrollment", + "authMethod": "beckn:authMethod", + "mobile": "beckn:mobile", + "otp": "beckn:otp", + "nguid": "beckn:nguid", + "accessToken": "beckn:accessToken", + "tokenType": "beckn:tokenType", + "idToken": "beckn:idToken", + "refreshToken": "beckn:refreshToken", + "scope": "beckn:scope", + "issuer": { "@id": "beckn:issuer", "@type": "@id" }, + "subject": "beckn:subject", + "verified": "beckn:verified", + "meterId": "beckn:meterId", + "meterNumber": "beckn:meterNumber", + "utilityId": "beckn:utilityId", + "utilityCustomerId": "beckn:utilityCustomerId", + "connectionType": "beckn:connectionType", + "sanctionedLoad": "beckn:sanctionedLoad" + } + ] +} diff --git a/specification/schema/EnergyEnrollment/v0.2/vocab.jsonld b/specification/schema/EnergyEnrollment/v0.2/vocab.jsonld new file mode 100644 index 00000000..884fc3b6 --- /dev/null +++ b/specification/schema/EnergyEnrollment/v0.2/vocab.jsonld @@ -0,0 +1,558 @@ +{ + "@context": { + "@version": 1.1, + "@vocab": "https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/#", + "beckn": "../vocab.jsonld", + "did": "https://www.w3.org/ns/did/v1#", + "schema": "https://schema.org/", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "owl": "http://www.w3.org/2002/07/owl#", + "vc": "https://www.w3.org/2018/credentials#", + + "EnergyEnrollment": { + "@id": "EnergyEnrollment", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:ProgramMembership" }, + "rdfs:comment": "Program enrollment/subscription. Extends schema:ProgramMembership for energy-specific enrollment flows. Reusable pattern for any subscription-based service (telecom, utilities, memberships)." + }, + + "VerifiableCredential": { + "@id": "vc:VerifiableCredential", + "@type": "@id", + "rdfs:comment": "A W3C Verifiable Credential (https://www.w3.org/TR/vc-data-model-2.0/) used in enrollment. This is a wrapper/reference object that contains the credential data (as JWT or JSON-LD), metadata, and URLs. The actual credential follows W3C VC Data Model v2.0 structure." + }, + + "CredentialVerification": { + "@id": "CredentialVerification", + "@type": "@id", + "rdfs:comment": "Results of credential verification performed by BPP. Contains status and list of verified credentials." + }, + + "ConflictCheck": { + "@id": "ConflictCheck", + "@type": "@id", + "rdfs:comment": "Results of conflict checking with existing enrollments. Indicates if conflicts exist and provides details of conflicting enrollments." + }, + + "ConflictingEnrollment": { + "@id": "ConflictingEnrollment", + "@type": "@id", + "rdfs:comment": "Details of a conflicting enrollment that prevents the requested enrollment from proceeding." + }, + + "VerifiedCredential": { + "@id": "VerifiedCredential", + "@type": "@id", + "rdfs:comment": "Details of a credential that has been verified by the BPP, including verification timestamp." + }, + + "ConsentRevocation": { + "@id": "ConsentRevocation", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:CancelAction" }, + "rdfs:comment": "Consent revocation. Extends schema:CancelAction for revoking consent/permissions." + }, + + "Unenrollment": { + "@id": "Unenrollment", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:LeaveAction" }, + "rdfs:comment": "Unenrollment/unsubscription. Extends schema:LeaveAction for leaving a program/membership." + }, + + "Customer": { + "@id": "beckn:Customer", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:Person" }, + "rdfs:comment": "Customer/subscriber entity. Extends schema:Person. Represents the user being enrolled in a program. Can also be schema:Organization for business subscriptions." + }, + + "Instrument": { + "@id": "beckn:Instrument", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:ItemList" }, + "rdfs:comment": "Collection of assets (meters, DERs) associated with an enrollment. Extends schema:ItemList as a container for enrollable items." + }, + + "Meter": { + "@id": "beckn:Meter", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:Product" }, + "rdfs:comment": "Electricity meter entity. Extends schema:Product. Represents a physical meter tracking consumption, generation, or net flow." + }, + + "DER": { + "@id": "beckn:DER", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:Product" }, + "rdfs:comment": "Distributed Energy Resource. Extends schema:Product. Represents a distributed asset such as solar PV, EV, home batteries, V2G, or smart loads." + }, + + "enrollmentId": { + "@id": "enrollmentId", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:membershipNumber" }, + "rdfs:comment": "Unique identifier for the enrollment/subscription. Equivalent to schema:membershipNumber." + }, + + "programId": { + "@id": "programId", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:programName" }, + "rdfs:comment": "Identifier/name of the program. Equivalent to schema:programName." + }, + + "status": { + "@id": "status", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:reservationStatus" }, + "rdfs:comment": "Enrollment status. Equivalent to schema:reservationStatus. Values: ACTIVE (Confirmed), PENDING (Pending), CANCELLED (Cancelled), SUSPENDED (Hold)." + }, + + "startDate": { + "@id": "startDate", + "@type": "xsd:dateTime", + "owl:equivalentProperty": { "@id": "schema:validFrom" }, + "rdfs:comment": "When enrollment becomes active. Equivalent to schema:validFrom." + }, + + "endDate": { + "@id": "endDate", + "@type": "xsd:dateTime", + "owl:equivalentProperty": { "@id": "schema:validThrough" }, + "rdfs:comment": "When enrollment expires/ends. Equivalent to schema:validThrough." + }, + + "enrolledAt": { + "@id": "enrolledAt", + "@type": "xsd:dateTime", + "owl:equivalentProperty": { "@id": "schema:dateCreated" }, + "rdfs:comment": "When enrollment was created/confirmed. Equivalent to schema:dateCreated." + }, + + "meters": { + "@id": "meters", + "@type": "@id", + "@container": "@set", + "rdfs:comment": "Array of MeterEnrollment objects specifying meters to enroll. Required in confirm request - order will only be confirmed if at least one meter is specified." + }, + + "ders": { + "@id": "ders", + "@type": "@id", + "@container": "@set", + "rdfs:comment": "Array of DER identifiers associated with the enrollment. Used in enrollment credentials." + }, + + "credential": { + "@id": "credential", + "@type": "@id", + "rdfs:comment": "Enrollment credential object. Contains the signed Verifiable Credential proving enrollment." + }, + + "credentialId": { + "@id": "credentialId", + "@type": "xsd:string", + "rdfs:comment": "Unique identifier for the credential. Used to reference credentials in verification and conflict checking." + }, + + "credentialData": { + "@id": "credentialData", + "@type": "xsd:string", + "rdfs:comment": "The credential data itself, typically a JWT or JSON-LD string containing the W3C Verifiable Credential (https://www.w3.org/TR/vc-data-model-2.0/). When decoded, must conform to W3C VC Data Model v2.0 structure." + }, + + "credentialUrl": { + "@id": "credentialUrl", + "@type": "@id", + "rdfs:comment": "URL where the credential can be accessed or retrieved. Used for enrollment credentials returned in on_confirm." + }, + + "verificationUrl": { + "@id": "verificationUrl", + "@type": "@id", + "rdfs:comment": "URL for verifying the credential. Used for third-party verification of enrollment credentials." + }, + + "format": { + "@id": "format", + "@type": "xsd:string", + "rdfs:comment": "Credential format as per W3C VC Data Model v2.0. Values: VC-JWT (JWT-encoded VC), VC-JSON-LD (JSON-LD encoded VC), or other W3C Verifiable Credential formats." + }, + + "issuedAt": { + "@id": "vc:issuanceDate", + "@type": "xsd:dateTime", + "rdfs:comment": "Timestamp when the credential was issued (ISO 8601). Maps to W3C VC issuanceDate property." + }, + + "expiresAt": { + "@id": "vc:expirationDate", + "@type": "xsd:dateTime", + "rdfs:comment": "Timestamp when the credential expires (ISO 8601). Maps to W3C VC expirationDate property. May be null for non-expiring credentials." + }, + + "credentialVerification": { + "@id": "credentialVerification", + "@type": "@id", + "rdfs:comment": "Credential verification results object. Returned in on_init response after BPP verifies provided credentials." + }, + + "verifiedCredentials": { + "@id": "verifiedCredentials", + "@type": "@id", + "@container": "@set", + "rdfs:comment": "Array of VerifiedCredential objects representing credentials that were successfully verified." + }, + + "verifiedAt": { + "@id": "verifiedAt", + "@type": "xsd:dateTime", + "rdfs:comment": "Timestamp when the credential was verified by BPP (ISO 8601)." + }, + + "conflictCheck": { + "@id": "conflictCheck", + "@type": "@id", + "rdfs:comment": "Conflict check results object. Returned in on_init response after BPP checks for conflicts with existing enrollments." + }, + + "hasConflict": { + "@id": "hasConflict", + "@type": "xsd:boolean", + "rdfs:comment": "Boolean indicating whether a conflict exists with existing enrollments. True if conflict found, false otherwise." + }, + + "conflictingEnrollments": { + "@id": "conflictingEnrollments", + "@type": "@id", + "@container": "@set", + "rdfs:comment": "Array of ConflictingEnrollment objects detailing conflicts found during conflict checking." + }, + + "conflictReason": { + "@id": "conflictReason", + "@type": "xsd:string", + "rdfs:comment": "Human-readable description of why the conflict exists. Explains the nature of the conflict." + }, + + "conflictType": { + "@id": "conflictType", + "@type": "xsd:string", + "rdfs:comment": "Type of conflict. Values: METER_ALREADY_ENROLLED, DER_ALREADY_ENROLLED, PROGRAM_CONFLICT, etc." + }, + + "checkedAt": { + "@id": "checkedAt", + "@type": "xsd:dateTime", + "rdfs:comment": "Timestamp when the conflict check was performed by BPP (ISO 8601)." + }, + + "message": { + "@id": "message", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:description" }, + "rdfs:comment": "Human-readable message. Equivalent to schema:description." + }, + + "loggedAt": { + "@id": "loggedAt", + "@type": "xsd:dateTime", + "rdfs:comment": "Timestamp when the enrollment was logged in BPP's audit system (ISO 8601). Returned in on_confirm response." + }, + + "logReference": { + "@id": "logReference", + "@type": "xsd:string", + "rdfs:comment": "Reference identifier for the enrollment log entry. Used for audit trail and record keeping." + }, + + "credentials": { + "@id": "credentials", + "@type": "@id", + "@container": "@set", + "rdfs:comment": "Array of VerifiableCredential objects (W3C VC Data Model v2.0) provided in init request. Contains VCs for meter ownership, program eligibility, DER certification, etc." + }, + + "existingEnrollments": { + "@id": "existingEnrollments", + "@type": "@id", + "@container": "@set", + "rdfs:comment": "Array of VerifiableCredential objects (W3C VC Data Model v2.0) representing existing enrollments. Provided in init request to help BPP check for conflicts." + }, + + "type": { + "@id": "vc:type", + "@type": "xsd:string", + "rdfs:comment": "Credential type as per W3C VC Data Model v2.0. Must include 'VerifiableCredential' plus specific types: MeterOwnershipCredential, ProgramEligibilityCredential, DERCertificationCredential, ProgramEnrollmentCredential." + }, + + "derId": { + "@id": "derId", + "@type": "xsd:string", + "rdfs:comment": "DER identifier associated with a DER certification credential. Links the credential to a specific DER." + }, + + "updateType": { + "@id": "updateType", + "@type": "xsd:string", + "rdfs:comment": "Type of update being performed. Values: CONSENT_REVOCATION, UNENROLLMENT." + }, + + "consentRevocation": { + "@id": "consentRevocation", + "@type": "@id", + "rdfs:comment": "Consent revocation details object. Contains information about the consent being revoked." + }, + + "unenrollment": { + "@id": "unenrollment", + "@type": "@id", + "rdfs:comment": "Unenrollment details object. Contains information about the enrollment being cancelled." + }, + + "consentCredentialId": { + "@id": "consentCredentialId", + "@type": "xsd:string", + "rdfs:comment": "Identifier of the consent credential being revoked. References the Verifiable Credential ID." + }, + + "consentType": { + "@id": "consentType", + "@type": "xsd:string", + "rdfs:comment": "Type of consent being revoked. Values: DATA_COLLECTION, DER_CONTROL, CROSS_UTILITY_SHARING." + }, + + "revokedAt": { + "@id": "revokedAt", + "@type": "xsd:dateTime", + "owl:equivalentProperty": { "@id": "schema:endTime" }, + "rdfs:comment": "When revocation occurred. Equivalent to schema:endTime for actions." + }, + + "effectiveDate": { + "@id": "effectiveDate", + "@type": "xsd:dateTime", + "owl:equivalentProperty": { "@id": "schema:scheduledTime" }, + "rdfs:comment": "When revocation takes effect. Equivalent to schema:scheduledTime." + }, + + "statusListUrl": { + "@id": "statusListUrl", + "@type": "@id", + "rdfs:comment": "URL of the W3C VC status list where the revoked credential is recorded. Used for verification." + }, + + "statusListIndex": { + "@id": "statusListIndex", + "@type": "xsd:string", + "rdfs:comment": "Index in the status list where this credential's revocation status is recorded. Used for efficient status checking." + }, + + "cancelledAt": { + "@id": "cancelledAt", + "@type": "xsd:dateTime", + "rdfs:comment": "Timestamp when the enrollment was cancelled (ISO 8601)." + }, + + "enrollmentCredentialStatus": { + "@id": "enrollmentCredentialStatus", + "@type": "@id", + "rdfs:comment": "Status information for the enrollment credential after revocation. Contains status list details." + }, + + "consentsRevoked": { + "@id": "consentsRevoked", + "@type": "@id", + "@container": "@set", + "rdfs:comment": "Array of consent credentials that were revoked as part of unenrollment." + }, + + "revokeAllConsents": { + "@id": "revokeAllConsents", + "@type": "xsd:boolean", + "rdfs:comment": "Boolean indicating whether all associated consents should be revoked during unenrollment." + }, + + "UserAuth": { + "@id": "UserAuth", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:AuthenticateAction" }, + "rdfs:comment": "User authentication base type. Extends schema:AuthenticateAction." + }, + + "UserAuthRequest": { + "@id": "UserAuthRequest", + "@type": "@id", + "rdfs:subClassOf": { "@id": "UserAuth" }, + "rdfs:comment": "User authentication request (BAP → BPP). Contains credentials for verification." + }, + + "UserAuthResponse": { + "@id": "UserAuthResponse", + "@type": "@id", + "rdfs:subClassOf": { "@id": "UserAuth" }, + "rdfs:comment": "User authentication response (BPP → BAP). Contains verification results." + }, + + "userAuth": { + "@id": "userAuth", + "@type": "@id", + "owl:equivalentProperty": { "@id": "schema:actionStatus" }, + "rdfs:comment": "Authentication object. UserAuthRequest for requests, UserAuthResponse for responses." + }, + + "OtpAuthRequest": { + "@id": "OtpAuthRequest", + "@type": "@id", + "rdfs:subClassOf": { "@id": "UserAuthRequest" }, + "rdfs:comment": "OTP authentication request. Contains mobile number and optionally OTP+nguid." + }, + + "OtpAuthResponse": { + "@id": "OtpAuthResponse", + "@type": "@id", + "rdfs:subClassOf": { "@id": "UserAuthResponse" }, + "rdfs:comment": "OTP authentication response. Contains nguid, verification status, and message." + }, + + "OAuth2AuthRequest": { + "@id": "OAuth2AuthRequest", + "@type": "@id", + "rdfs:subClassOf": { "@id": "UserAuthRequest" }, + "rdfs:comment": "OAuth2/OIDC authentication request. Contains JWT tokens (accessToken, idToken)." + }, + + "OAuth2AuthResponse": { + "@id": "OAuth2AuthResponse", + "@type": "@id", + "rdfs:subClassOf": { "@id": "UserAuthResponse" }, + "rdfs:comment": "OAuth2/OIDC authentication response. Contains verification result and extracted claims." + }, + + "authMethod": { + "@id": "authMethod", + "@type": "xsd:string", + "rdfs:comment": "Authentication method discriminator. Values: OTP, OAUTH2, OIDC." + }, + + "accessToken": { + "@id": "accessToken", + "@type": "xsd:string", + "rdfs:comment": "OAuth2 access token (bearer token) for authentication." + }, + + "tokenType": { + "@id": "tokenType", + "@type": "xsd:string", + "rdfs:comment": "Token type, usually 'Bearer' for OAuth2." + }, + + "idToken": { + "@id": "idToken", + "@type": "xsd:string", + "rdfs:comment": "OIDC ID token (JWT) containing user identity claims." + }, + + "refreshToken": { + "@id": "refreshToken", + "@type": "xsd:string", + "rdfs:comment": "OAuth2 refresh token for obtaining new access tokens." + }, + + "scope": { + "@id": "scope", + "@type": "xsd:string", + "rdfs:comment": "OAuth2 scopes granted to the token. Space-separated list." + }, + + "issuer": { + "@id": "issuer", + "@type": "@id", + "owl:equivalentProperty": { "@id": "schema:issuedBy" }, + "rdfs:comment": "OIDC issuer URL. Equivalent to schema:issuedBy." + }, + + "subject": { + "@id": "subject", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:identifier" }, + "rdfs:comment": "Subject identifier (user ID) from token. Related to schema:identifier." + }, + + "MeterEnrollment": { + "@id": "MeterEnrollment", + "@type": "@id", + "rdfs:subClassOf": { "@id": "schema:IndividualProduct" }, + "rdfs:comment": "A specific product instance for enrollment. Extends schema:IndividualProduct. Represents a device/asset being subscribed (meter, SIM, device, etc.)." + }, + + "meterId": { + "@id": "meterId", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:serialNumber" }, + "rdfs:comment": "Primary device identifier. Equivalent to schema:serialNumber." + }, + + "meterNumber": { + "@id": "meterNumber", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:productID" }, + "rdfs:comment": "Secondary/display identifier. Equivalent to schema:productID." + }, + + "utilityId": { + "@id": "utilityId", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:provider" }, + "rdfs:comment": "Service provider identifier. Related to schema:provider." + }, + + "utilityCustomerId": { + "@id": "utilityCustomerId", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:accountId" }, + "rdfs:comment": "Customer account identifier at the utility. Equivalent to schema:accountId. Links the authenticated user to their billing account." + }, + + "connectionType": { + "@id": "connectionType", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:category" }, + "rdfs:comment": "Service category. Equivalent to schema:category (residential, commercial, etc.)." + }, + + "sanctionedLoad": { + "@id": "sanctionedLoad", + "@type": "xsd:decimal", + "rdfs:comment": "Capacity/limit for the connection (kW). Domain-specific; no direct schema.org equivalent." + }, + + "mobile": { + "@id": "mobile", + "@type": "xsd:string", + "owl:equivalentProperty": { "@id": "schema:telephone" }, + "rdfs:comment": "Mobile phone number. Equivalent to schema:telephone." + }, + + "otp": { + "@id": "otp", + "@type": "xsd:string", + "rdfs:comment": "One-time password entered by user for verification. Sent by BPP via SMS to mobile number." + }, + + "nguid": { + "@id": "nguid", + "@type": "xsd:string", + "rdfs:comment": "Network GUID / session token for OTP verification. Generated by BPP, returned in on_init, required in confirm." + }, + + "verified": { + "@id": "verified", + "@type": "xsd:boolean", + "rdfs:comment": "Boolean indicating whether OTP verification was successful. Only present in on_confirm response." + } + } +} + diff --git a/specification/schema/EnergyTrade/v0.3/attributes.yaml b/specification/schema/EnergyTrade/v0.3/attributes.yaml new file mode 100644 index 00000000..3993667c --- /dev/null +++ b/specification/schema/EnergyTrade/v0.3/attributes.yaml @@ -0,0 +1,373 @@ +openapi: 3.1.1 +info: + title: Energy Trade — Combined Attribute Schemas (v0.3) + version: 0.3.0 + x-profile-id: profiles/energy-trade/energy_trade/v0.3 + description: > + Combined attribute schemas for P2P energy trading. This file consolidates all + energy trading attribute schemas for easier cross-referencing and maintenance. + + Includes schemas for: + - EnergyTradeOffer (Offer.offerAttributes) - Pricing models and delivery windows + - EnergyTradeOrder (Order.orderAttributes) - Platform and utility identifiers + - EnergyTradeDelivery (orderItemAttributes.fulfillmentAttributes) - Delivery tracking + - EnergyResource (Item.itemAttributes) - Energy source characteristics + - EnergyCustomer (Buyer.buyerAttributes, Provider.providerAttributes) - Customer info: meterId, sanctionedLoad, utilityCustomerId, utilityId + - EnergyOrderItem (orderItemAttributes) - Order item wrapper + +components: + schemas: + ######################################################################## + # OFFER.ATTRIBUTES — EnergyTradeOffer (P2P Energy Trading) + ######################################################################## + EnergyTradeOffer: + type: object + additionalProperties: false + required: [pricingModel] + x-jsonld: + "@context": ./context.jsonld + "@type": EnergyTradeOffer + description: > + Offer attributes for P2P energy trading. Attached to Offer.offerAttributes + to provide pricing models, availability windows, and delivery details. + NOTE: Price (beckn:price) is specified on the parent Offer object, not here. + The price.applicableQuantity specifies the max energy quantity for this delivery window. + properties: + + pricingModel: + type: string + enum: [PER_KWH, TIME_OF_DAY, SUBSCRIPTION, FIXED] + description: Pricing model classification used for the energy trade offer. + example: "PER_KWH" + x-jsonld: { "@id": pricingModel } + + validityWindow: + allOf: + - $ref: 'https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/attributes.yaml#/components/schemas/TimePeriod' + - type: object + description: > + Time window during which this offer can be selected/accepted. Typically set + to expire before delivery starts (e.g., 4 hours before delivery start time) + to allow for scheduling and grid coordination. After this window closes, + the offer is no longer available for selection. + required: ["schema:startTime", "schema:endTime"] + x-jsonld: { "@id": validityWindow } + + deliveryWindow: + allOf: + - $ref: 'https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/attributes.yaml#/components/schemas/TimePeriod' + - type: object + description: > + Specific time period (start and end time) when energy delivery occurs. + Different from validityWindow which indicates when the offer can be selected. + This represents the actual delivery time window. All times MUST be in UTC + (ISO 8601 with Z suffix). + required: ["schema:startTime", "schema:endTime"] + properties: + "schema:startTime": + type: string + format: date-time + pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$' + description: Start time in UTC (ISO 8601 format with Z suffix). + example: "2025-06-15T09:00:00Z" + "schema:endTime": + type: string + format: date-time + pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$' + description: End time in UTC (ISO 8601 format with Z suffix). + example: "2025-06-15T10:00:00Z" + x-jsonld: { "@id": deliveryWindow } + + ######################################################################## + # ORDER.ATTRIBUTES — EnergyTradeOrder (P2P Energy Trading) + ######################################################################## + EnergyTradeOrder: + type: object + additionalProperties: false + required: [bap_id, bpp_id] + x-jsonld: + "@context": ./context.jsonld + "@type": EnergyTradeOrder + description: > + Order attributes for P2P energy trading. Attached to Order.orderAttributes + to identify BAP and BPP participants involved in a trade. + NOTE: Utility IDs for inter-discom trading are captured in EnergyCustomer + (buyerAttributes.utilityId and providerAttributes.utilityId). + properties: + + bap_id: + type: string + description: Beckn Application Platform (BAP) identifier. The subscriber ID of the buyer/consumer platform initiating the trade order. + example: "bap.energymarket.io" + x-jsonld: { "@id": bap_id } + + bpp_id: + type: string + description: Beckn Provider Platform (BPP) identifier. The subscriber ID of the seller/provider platform fulfilling the trade order. + example: "bpp.solarprovider.io" + x-jsonld: { "@id": bpp_id } + + total_quantity: + allOf: + - $ref: 'https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/attributes.yaml#/components/schemas/Quantity' + - type: object + description: > + Total quantity of energy for this trade order. Units should be in kWh. + properties: + unitText: + default: "kWh" + unitCode: + default: "KWH" + example: + unitQuantity: 50.0 + unitText: "kWh" + unitCode: "KWH" + x-jsonld: { "@id": total_quantity } + + ######################################################################## + # FULFILLMENT.ATTRIBUTES — EnergyTradeDelivery (P2P Energy Trading) + ######################################################################## + EnergyTradeDelivery: + type: object + additionalProperties: false + x-jsonld: + "@context": ./context.jsonld + "@type": EnergyTradeDelivery + description: > + Fulfillment attributes for energy trade deliveries. Attached to + orderItemAttributes.fulfillmentAttributes to track physical transfer of energy + including delivery status, meter readings, and energy allocation data. + consumedEnergy = energy TO customer (imported), + producedEnergy = energy FROM customer (exported to grid). + properties: + + deliveryStatus: + type: string + enum: [PENDING, IN_PROGRESS, COMPLETED, FAILED] + description: Delivery status for the energy transfer. + example: "IN_PROGRESS" + x-jsonld: { "@id": deliveryStatus } + + deliveryMode: + type: string + enum: [EV_CHARGING, BATTERY_SWAP, V2G, GRID_INJECTION] + description: Mode of energy delivery for this fulfillment. + example: "GRID_INJECTION" + x-jsonld: { "@id": deliveryMode } + + deliveredQuantity: + type: number + minimum: 0 + description: Total quantity delivered so far in kilowatt-hours (kWh). + example: 15.0 + x-jsonld: { "@id": deliveredQuantity } + + meterReadings: + type: array + description: > + Array of meter readings for this orderItem. Each reading covers a time window + and reports energy delivered/received during that period. Times are in UTC (ISO 8601 with Z suffix). + items: + type: object + additionalProperties: false + properties: + beckn:timeWindow: + type: object + description: Time period for this meter reading (UTC). + additionalProperties: false + properties: + "@type": + type: string + enum: ["beckn:TimePeriod"] + schema:startTime: + type: string + format: date-time + pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$' + description: Start time in UTC (ISO 8601 with Z suffix). + schema:endTime: + type: string + format: date-time + pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$' + description: End time in UTC (ISO 8601 with Z suffix). + required: ["schema:startTime", "schema:endTime"] + consumedEnergy: + type: number + minimum: 0 + description: > + Energy consumed by the customer (imported from grid) in this time window (kWh). + Per IEC 61968/ESPI flowDirection=1. + x-jsonld: { "@id": consumedEnergy } + producedEnergy: + type: number + minimum: 0 + description: > + Energy produced by the customer (exported to grid) in this time window (kWh). + Per IEC 61968/ESPI flowDirection=19. + x-jsonld: { "@id": producedEnergy } + allocatedEnergy: + type: number + minimum: 0 + description: Net energy allocated for this trade in this time window (kWh). + x-jsonld: { "@id": allocatedEnergy } + unit: + type: string + enum: ["kWh", "MWh", "Wh"] + default: "kWh" + description: Unit of measurement for energy values. + x-jsonld: { "@id": "schema:unitText" } + required: ["beckn:timeWindow", "allocatedEnergy", "unit"] + x-jsonld: { "@id": meterReadings } + + curtailedQuantity: + type: number + minimum: 0 + description: > + Quantity curtailed from original contracted amount (kWh). + Used by BAP/BPP to reconcile payment vs. original contracted quantity. + example: 5.0 + x-jsonld: { "@id": curtailedQuantity } + + curtailmentReason: + type: string + enum: [GRID_OUTAGE, EMERGENCY, CONGESTION, MAINTENANCE, OTHER] + description: Reason for curtailment. Useful for audit trail and dispute resolution. + example: "GRID_OUTAGE" + x-jsonld: { "@id": curtailmentReason } + + lastUpdated: + type: string + format: date-time + description: Last delivery update timestamp in UTC (ISO 8601 with Z suffix). + example: "2024-10-04T15:30:00Z" + x-jsonld: { "@id": "schema:dateModified" } + + ######################################################################## + # ITEM.ATTRIBUTES — EnergyResource (P2P Energy Trading) + ######################################################################## + EnergyResource: + type: object + additionalProperties: false + x-jsonld: + "@context": ./context.jsonld + "@type": EnergyResource + description: > + Item attributes for energy resources. Attached to Item.itemAttributes to provide + energy-specific characteristics including source type and meter identifiers. + properties: + + sourceType: + type: string + enum: [SOLAR, BATTERY, GRID, HYBRID, RENEWABLE] + description: Type of energy source. Source verification occurs at onboarding but can change post-onboarding (e.g., switching from solar to diesel). Source type influences price but not workflow. + example: "SOLAR" + x-jsonld: { "@id": sourceType } + + meterId: + type: string + description: Source meter identifier in DER address format (der://meter/{id}). Used for discovery and fulfillment tracking. + example: "der://meter/100200300" + x-jsonld: { "@id": meterId } + + ######################################################################## + # CUSTOMER.ATTRIBUTES — EnergyCustomer (P2P Energy Trading & Enrollment) + ######################################################################## + EnergyCustomer: + type: object + additionalProperties: false + required: ["meterId"] + x-jsonld: + "@context": ./context.jsonld + "@type": EnergyCustomer + description: > + Customer attributes for energy flows. Used for consumers, producers, or prosumers in: + - orderItemAttributes (init request): Contains meterId for delivery destination + - orderItemAttributes (responses): Contains meterId for delivery destination + - buyerAttributes (enrollment): Contains meterId and sanctionedLoad for customer identification + properties: + + meterId: + type: string + description: > + Meter identifier in DER address format (der://meter/{id}). Used for customer identification + and energy delivery tracking in P2P trading flows. + example: "der://meter/98765456" + x-jsonld: { "@id": meterId } + + sanctionedLoad: + type: number + minimum: 0 + description: > + Sanctioned load capacity in kilowatts (kW). Optional field representing the approved + electrical load capacity for the customer's connection. Used for load management and + regulatory compliance. + example: 15.0 + x-jsonld: { "@id": sanctionedLoad } + + utilityCustomerId: + type: string + description: > + Customer's account identifier with the utility company (e.g., PG&E customer number). + Used for billing, service identification, and utility system integration. + example: "UTIL-CUST-123456" + x-jsonld: { "@id": utilityCustomerId } + + utilityId: + type: string + description: > + Utility/DISCOM identifier for the customer's service territory (e.g., "TPDDL-DL", "BESCOM-KA"). + Used in inter-utility/inter-DISCOM P2P trading to identify which utility serves this customer. + Should match the corresponding utilityIdSeller or utilityIdBuyer in orderAttributes for + cross-utility transactions. + example: "TPDDL-DL" + x-jsonld: { "@id": utilityId } + + ######################################################################## + # ORDERITEM.ATTRIBUTES — EnergyOrderItem (P2P Energy Trading) + ######################################################################## + EnergyOrderItem: + type: object + additionalProperties: false + required: + - providerAttributes + x-jsonld: + "@context": ./context.jsonld + "@type": EnergyOrderItem + description: > + Order item attributes for P2P energy trading. Wraps customer information + and optional fulfillment tracking data. Use this schema for + beckn:orderItemAttributes in P2P energy trading flows. + properties: + + providerAttributes: + type: object + description: > + Provider/customer information for this order item, including meter ID and utility account. + additionalProperties: true + properties: + "@context": + type: string + format: uri + description: URI to the EnergyCustomer context.jsonld + "@type": + type: string + enum: ["EnergyCustomer"] + description: Type identifier for provider attributes + x-jsonld: { "@id": providerAttributes } + + fulfillmentAttributes: + type: object + description: > + Optional fulfillment tracking for this order item. + Only populated in on_status and on_update responses (not in init/confirm flows). + Contains delivery status, meter readings, and energy allocation data. + additionalProperties: true + properties: + "@context": + type: string + format: uri + description: URI to the EnergyTradeDelivery context.jsonld + "@type": + type: string + enum: ["EnergyTradeDelivery"] + description: Type identifier for fulfillment attributes + x-jsonld: { "@id": fulfillmentAttributes } diff --git a/specification/schema/EnergyTrade/v0.3/context.jsonld b/specification/schema/EnergyTrade/v0.3/context.jsonld new file mode 100644 index 00000000..4852b5f8 --- /dev/null +++ b/specification/schema/EnergyTrade/v0.3/context.jsonld @@ -0,0 +1,106 @@ +{ + "@context": { + "@version": 1.1, + "schema": "https://schema.org/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + "beckn": "./vocab.jsonld#", + + "name": "schema:name", + "description": "schema:description", + "price": "schema:price", + "priceCurrency": "schema:priceCurrency", + "startTime": "schema:startTime", + "endTime": "schema:endTime", + "amount": "schema:amount", + "currency": "schema:currency", + "lastUpdated": "schema:dateModified", + "unit": "schema:unitText", + + "EnergyTradeOffer": "beckn:EnergyTradeOffer", + "EnergyTradeOrder": "beckn:EnergyTradeOrder", + "EnergyTradeDelivery": "beckn:EnergyTradeDelivery", + "EnergyResource": "beckn:EnergyResource", + "EnergyCustomer": "beckn:EnergyCustomer", + "EnergyOrderItem": "beckn:EnergyOrderItem", + + "pricingModel": { + "@id": "beckn:pricingModel", + "@type": "@id" + }, + "validityWindow": "beckn:validityWindow", + "deliveryWindow": "beckn:deliveryWindow", + + "bap_id": "beckn:bap_id", + "bpp_id": "beckn:bpp_id", + "total_quantity": "beckn:total_quantity", + + "deliveryStatus": { + "@id": "beckn:deliveryStatus", + "@type": "@id" + }, + "deliveryMode": { + "@id": "beckn:deliveryMode", + "@type": "@id" + }, + "deliveredQuantity": "beckn:deliveredQuantity", + "meterReadings": "beckn:meterReadings", + "consumedEnergy": "beckn:consumedEnergy", + "producedEnergy": "beckn:producedEnergy", + "allocatedEnergy": "beckn:allocatedEnergy", + "curtailedQuantity": "beckn:curtailedQuantity", + "curtailmentReason": { + "@id": "beckn:curtailmentReason", + "@type": "@id" + }, + + "sourceType": { + "@id": "beckn:sourceType", + "@type": "@id" + }, + "meterId": "beckn:meterId", + + "sanctionedLoad": "beckn:sanctionedLoad", + "utilityCustomerId": "beckn:utilityCustomerId", + "utilityId": "beckn:utilityId", + + "providerAttributes": "beckn:providerAttributes", + "fulfillmentAttributes": "beckn:fulfillmentAttributes", + + "PER_KWH": "beckn:PricingModelPerKwh", + "PER-KWH": "beckn:PricingModelPerKwh", + "TIME_OF_DAY": "beckn:PricingModelTimeOfDay", + "TIME-OF-DAY": "beckn:PricingModelTimeOfDay", + "SUBSCRIPTION": "beckn:PricingModelSubscription", + "FIXED": "beckn:PricingModelFixed", + + "PENDING": "beckn:DeliveryStatusPending", + "IN_PROGRESS": "beckn:DeliveryStatusInProgress", + "IN-PROGRESS": "beckn:DeliveryStatusInProgress", + "COMPLETED": "beckn:DeliveryStatusCompleted", + "FAILED": "beckn:DeliveryStatusFailed", + + "EV_CHARGING": "beckn:DeliveryModeEvCharging", + "EV-CHARGING": "beckn:DeliveryModeEvCharging", + "BATTERY_SWAP": "beckn:DeliveryModeBatterySwap", + "BATTERY-SWAP": "beckn:DeliveryModeBatterySwap", + "V2G": "beckn:DeliveryModeV2G", + "GRID_INJECTION": "beckn:DeliveryModeGridInjection", + "GRID-INJECTION": "beckn:DeliveryModeGridInjection", + + "SOLAR": "beckn:SourceTypeSolar", + "BATTERY": "beckn:SourceTypeBattery", + "GRID": "beckn:SourceTypeGrid", + "HYBRID": "beckn:SourceTypeHybrid", + "RENEWABLE": "beckn:SourceTypeRenewable", + + "GRID_OUTAGE": "beckn:CurtailmentReasonGridOutage", + "EMERGENCY": "beckn:CurtailmentReasonEmergency", + "CONGESTION": "beckn:CurtailmentReasonCongestion", + "MAINTENANCE": "beckn:CurtailmentReasonMaintenance", + "OTHER": "beckn:CurtailmentReasonOther" + }, + + "@graph": [] +} diff --git a/specification/schema/EnergyTrade/v0.3/vocab.jsonld b/specification/schema/EnergyTrade/v0.3/vocab.jsonld new file mode 100644 index 00000000..e68877a9 --- /dev/null +++ b/specification/schema/EnergyTrade/v0.3/vocab.jsonld @@ -0,0 +1,402 @@ +{ + "@context": { + "@version": 1.1, + "beckn": "https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/main/schema/EnergyTrade/v0.3/#", + "schema": "https://schema.org/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "xsd": "http://www.w3.org/2001/XMLSchema#" + }, + "@graph": [ + { + "@id": "beckn:EnergyTradeOffer", + "@type": "rdfs:Class", + "rdfs:label": "Energy Trade Offer", + "rdfs:comment": "Offer attributes for P2P energy trading, attached to Offer.offerAttributes." + }, + { + "@id": "beckn:EnergyTradeOrder", + "@type": "rdfs:Class", + "rdfs:label": "Energy Trade Order", + "rdfs:comment": "Order attributes for P2P energy trading, attached to Order.orderAttributes." + }, + { + "@id": "beckn:EnergyTradeOrderInterUtility", + "@type": "rdfs:Class", + "rdfs:subClassOf": "beckn:EnergyTradeOrder", + "rdfs:label": "Energy Trade Order Inter-Utility", + "rdfs:comment": "Extended order attributes for inter-utility (inter-discom) P2P trading." + }, + { + "@id": "beckn:EnergyTradeDelivery", + "@type": "rdfs:Class", + "rdfs:label": "Energy Trade Delivery", + "rdfs:comment": "Fulfillment attributes for energy trade deliveries, attached to orderItemAttributes.fulfillmentAttributes." + }, + { + "@id": "beckn:EnergyResource", + "@type": "rdfs:Class", + "rdfs:label": "Energy Resource", + "rdfs:comment": "Item attributes for energy resources, attached to Item.itemAttributes." + }, + { + "@id": "beckn:EnergyCustomer", + "@type": "rdfs:Class", + "rdfs:label": "Energy Customer", + "rdfs:comment": "Customer attributes for energy flows, attached to Buyer.buyerAttributes or Provider.providerAttributes." + }, + { + "@id": "beckn:EnergyOrderItem", + "@type": "rdfs:Class", + "rdfs:label": "Energy Order Item", + "rdfs:comment": "Order item attributes wrapper for P2P energy trading, attached to beckn:orderItemAttributes." + }, + { + "@id": "beckn:pricingModel", + "@type": "rdf:Property", + "rdfs:label": "Pricing model", + "rdfs:comment": "Pricing model classification (PER_KWH, TIME_OF_DAY, SUBSCRIPTION, FIXED).", + "rdfs:domain": "beckn:EnergyTradeOffer", + "schema:rangeIncludes": "beckn:PricingModel" + }, + { + "@id": "beckn:validityWindow", + "@type": "rdf:Property", + "rdfs:label": "Validity window", + "rdfs:comment": "Time window when the offer can be selected/accepted.", + "rdfs:domain": "beckn:EnergyTradeOffer", + "schema:rangeIncludes": "schema:TimePeriod" + }, + { + "@id": "beckn:deliveryWindow", + "@type": "rdf:Property", + "rdfs:label": "Delivery window", + "rdfs:comment": "Specific time period when energy delivery occurs.", + "rdfs:domain": "beckn:EnergyTradeOffer", + "schema:rangeIncludes": "schema:TimePeriod" + }, + { + "@id": "beckn:bap_id", + "@type": "rdf:Property", + "rdfs:label": "BAP ID", + "rdfs:comment": "Beckn Application Platform (BAP) identifier.", + "rdfs:domain": "beckn:EnergyTradeOrder", + "rdfs:range": "xsd:string" + }, + { + "@id": "beckn:bpp_id", + "@type": "rdf:Property", + "rdfs:label": "BPP ID", + "rdfs:comment": "Beckn Provider Platform (BPP) identifier.", + "rdfs:domain": "beckn:EnergyTradeOrder", + "rdfs:range": "xsd:string" + }, + { + "@id": "beckn:total_quantity", + "@type": "rdf:Property", + "rdfs:label": "Total quantity", + "rdfs:comment": "Total quantity of energy in kilowatt-hours (kWh) for this trade order.", + "rdfs:domain": "beckn:EnergyTradeOrder", + "schema:rangeIncludes": "schema:Number" + }, + { + "@id": "beckn:utilityIdBuyer", + "@type": "rdf:Property", + "rdfs:label": "Utility ID Buyer", + "rdfs:comment": "Identifier of the buyer-side utility/distribution company (discom).", + "rdfs:domain": "beckn:EnergyTradeOrderInterUtility", + "rdfs:range": "xsd:string" + }, + { + "@id": "beckn:utilityIdSeller", + "@type": "rdf:Property", + "rdfs:label": "Utility ID Seller", + "rdfs:comment": "Identifier of the seller-side utility/distribution company (discom).", + "rdfs:domain": "beckn:EnergyTradeOrderInterUtility", + "rdfs:range": "xsd:string" + }, + { + "@id": "beckn:deliveryStatus", + "@type": "rdf:Property", + "rdfs:label": "Delivery status", + "rdfs:comment": "Delivery status for the energy transfer (PENDING, IN_PROGRESS, COMPLETED, FAILED).", + "rdfs:domain": "beckn:EnergyTradeDelivery", + "schema:rangeIncludes": "beckn:DeliveryStatus" + }, + { + "@id": "beckn:deliveryMode", + "@type": "rdf:Property", + "rdfs:label": "Delivery mode", + "rdfs:comment": "Mode of energy delivery (EV_CHARGING, BATTERY_SWAP, V2G, GRID_INJECTION).", + "schema:rangeIncludes": "beckn:DeliveryMode" + }, + { + "@id": "beckn:deliveredQuantity", + "@type": "rdf:Property", + "rdfs:label": "Delivered quantity", + "rdfs:comment": "Total quantity delivered so far in kilowatt-hours (kWh).", + "rdfs:domain": "beckn:EnergyTradeDelivery", + "schema:rangeIncludes": "schema:Number" + }, + { + "@id": "beckn:meterReadings", + "@type": "rdf:Property", + "rdfs:label": "Meter readings", + "rdfs:comment": "Array of meter readings for this orderItem.", + "rdfs:domain": "beckn:EnergyTradeDelivery", + "schema:rangeIncludes": "schema:ItemList" + }, + { + "@id": "beckn:consumedEnergy", + "@type": "rdf:Property", + "rdfs:label": "Consumed energy", + "rdfs:comment": "Energy consumed by the customer (imported from grid) in kWh.", + "schema:rangeIncludes": "schema:Number" + }, + { + "@id": "beckn:producedEnergy", + "@type": "rdf:Property", + "rdfs:label": "Produced energy", + "rdfs:comment": "Energy produced by the customer (exported to grid) in kWh.", + "schema:rangeIncludes": "schema:Number" + }, + { + "@id": "beckn:allocatedEnergy", + "@type": "rdf:Property", + "rdfs:label": "Allocated energy", + "rdfs:comment": "Net energy allocated for this trade in kWh.", + "schema:rangeIncludes": "schema:Number" + }, + { + "@id": "beckn:curtailedQuantity", + "@type": "rdf:Property", + "rdfs:label": "Curtailed quantity", + "rdfs:comment": "Quantity curtailed from original contracted amount (kWh).", + "rdfs:domain": "beckn:EnergyTradeDelivery", + "schema:rangeIncludes": "schema:Number" + }, + { + "@id": "beckn:curtailmentReason", + "@type": "rdf:Property", + "rdfs:label": "Curtailment reason", + "rdfs:comment": "Reason for curtailment (GRID_OUTAGE, EMERGENCY, CONGESTION, MAINTENANCE, OTHER).", + "rdfs:domain": "beckn:EnergyTradeDelivery", + "schema:rangeIncludes": "beckn:CurtailmentReason" + }, + { + "@id": "beckn:sourceType", + "@type": "rdf:Property", + "rdfs:label": "Source type", + "rdfs:comment": "Type of energy source (SOLAR, BATTERY, GRID, HYBRID, RENEWABLE).", + "rdfs:domain": "beckn:EnergyResource", + "schema:rangeIncludes": "beckn:SourceType" + }, + { + "@id": "beckn:meterId", + "@type": "rdf:Property", + "rdfs:label": "Meter ID", + "rdfs:comment": "Meter identifier in DER address format (der://meter/{id}).", + "rdfs:range": "xsd:string" + }, + { + "@id": "beckn:sanctionedLoad", + "@type": "rdf:Property", + "rdfs:label": "Sanctioned load", + "rdfs:comment": "Sanctioned load capacity in kilowatts (kW).", + "rdfs:domain": "beckn:EnergyCustomer", + "schema:rangeIncludes": "schema:Number" + }, + { + "@id": "beckn:utilityCustomerId", + "@type": "rdf:Property", + "rdfs:label": "Utility customer ID", + "rdfs:comment": "Customer's account identifier with the utility company.", + "rdfs:domain": "beckn:EnergyCustomer", + "rdfs:range": "xsd:string" + }, + { + "@id": "beckn:utilityId", + "@type": "rdf:Property", + "rdfs:label": "Utility ID", + "rdfs:comment": "Utility/DISCOM identifier for the customer's service territory.", + "rdfs:domain": "beckn:EnergyCustomer", + "rdfs:range": "xsd:string" + }, + { + "@id": "beckn:providerAttributes", + "@type": "rdf:Property", + "rdfs:label": "Provider attributes", + "rdfs:comment": "Provider/customer information for this order item.", + "rdfs:domain": "beckn:EnergyOrderItem" + }, + { + "@id": "beckn:fulfillmentAttributes", + "@type": "rdf:Property", + "rdfs:label": "Fulfillment attributes", + "rdfs:comment": "Optional fulfillment tracking for this order item.", + "rdfs:domain": "beckn:EnergyOrderItem" + }, + { + "@id": "beckn:PricingModel", + "@type": "schema:Enumeration", + "schema:name": "Pricing Model", + "rdfs:comment": "Enumeration of supported pricing models for energy trade offers." + }, + { + "@id": "beckn:PricingModelPerKwh", + "@type": "beckn:PricingModel", + "schema:name": "PER_KWH", + "schema:identifier": "PER_KWH" + }, + { + "@id": "beckn:PricingModelTimeOfDay", + "@type": "beckn:PricingModel", + "schema:name": "TIME_OF_DAY", + "schema:identifier": "TIME_OF_DAY" + }, + { + "@id": "beckn:PricingModelSubscription", + "@type": "beckn:PricingModel", + "schema:name": "SUBSCRIPTION", + "schema:identifier": "SUBSCRIPTION" + }, + { + "@id": "beckn:PricingModelFixed", + "@type": "beckn:PricingModel", + "schema:name": "FIXED", + "schema:identifier": "FIXED" + }, + { + "@id": "beckn:DeliveryStatus", + "@type": "schema:Enumeration", + "schema:name": "Delivery Status", + "rdfs:comment": "Enumeration of delivery statuses." + }, + { + "@id": "beckn:DeliveryStatusPending", + "@type": "beckn:DeliveryStatus", + "schema:name": "PENDING", + "schema:identifier": "PENDING" + }, + { + "@id": "beckn:DeliveryStatusInProgress", + "@type": "beckn:DeliveryStatus", + "schema:name": "IN_PROGRESS", + "schema:identifier": "IN_PROGRESS" + }, + { + "@id": "beckn:DeliveryStatusCompleted", + "@type": "beckn:DeliveryStatus", + "schema:name": "COMPLETED", + "schema:identifier": "COMPLETED" + }, + { + "@id": "beckn:DeliveryStatusFailed", + "@type": "beckn:DeliveryStatus", + "schema:name": "FAILED", + "schema:identifier": "FAILED" + }, + { + "@id": "beckn:DeliveryMode", + "@type": "schema:Enumeration", + "schema:name": "Delivery Mode", + "rdfs:comment": "Enumeration of energy delivery modes." + }, + { + "@id": "beckn:DeliveryModeEvCharging", + "@type": "beckn:DeliveryMode", + "schema:name": "EV_CHARGING", + "schema:identifier": "EV_CHARGING" + }, + { + "@id": "beckn:DeliveryModeBatterySwap", + "@type": "beckn:DeliveryMode", + "schema:name": "BATTERY_SWAP", + "schema:identifier": "BATTERY_SWAP" + }, + { + "@id": "beckn:DeliveryModeV2G", + "@type": "beckn:DeliveryMode", + "schema:name": "V2G", + "schema:identifier": "V2G" + }, + { + "@id": "beckn:DeliveryModeGridInjection", + "@type": "beckn:DeliveryMode", + "schema:name": "GRID_INJECTION", + "schema:identifier": "GRID_INJECTION" + }, + { + "@id": "beckn:SourceType", + "@type": "schema:Enumeration", + "schema:name": "Source Type", + "rdfs:comment": "Enumeration of energy source types." + }, + { + "@id": "beckn:SourceTypeSolar", + "@type": "beckn:SourceType", + "schema:name": "SOLAR", + "schema:identifier": "SOLAR" + }, + { + "@id": "beckn:SourceTypeBattery", + "@type": "beckn:SourceType", + "schema:name": "BATTERY", + "schema:identifier": "BATTERY" + }, + { + "@id": "beckn:SourceTypeGrid", + "@type": "beckn:SourceType", + "schema:name": "GRID", + "schema:identifier": "GRID" + }, + { + "@id": "beckn:SourceTypeHybrid", + "@type": "beckn:SourceType", + "schema:name": "HYBRID", + "schema:identifier": "HYBRID" + }, + { + "@id": "beckn:SourceTypeRenewable", + "@type": "beckn:SourceType", + "schema:name": "RENEWABLE", + "schema:identifier": "RENEWABLE" + }, + { + "@id": "beckn:CurtailmentReason", + "@type": "schema:Enumeration", + "schema:name": "Curtailment Reason", + "rdfs:comment": "Enumeration of reasons for energy curtailment." + }, + { + "@id": "beckn:CurtailmentReasonGridOutage", + "@type": "beckn:CurtailmentReason", + "schema:name": "GRID_OUTAGE", + "schema:identifier": "GRID_OUTAGE" + }, + { + "@id": "beckn:CurtailmentReasonEmergency", + "@type": "beckn:CurtailmentReason", + "schema:name": "EMERGENCY", + "schema:identifier": "EMERGENCY" + }, + { + "@id": "beckn:CurtailmentReasonCongestion", + "@type": "beckn:CurtailmentReason", + "schema:name": "CONGESTION", + "schema:identifier": "CONGESTION" + }, + { + "@id": "beckn:CurtailmentReasonMaintenance", + "@type": "beckn:CurtailmentReason", + "schema:name": "MAINTENANCE", + "schema:identifier": "MAINTENANCE" + }, + { + "@id": "beckn:CurtailmentReasonOther", + "@type": "beckn:CurtailmentReason", + "schema:name": "OTHER", + "schema:identifier": "OTHER" + } + ] +} diff --git a/testnet/ev-charging-devkit/README.md b/testnet/ev-charging-devkit/README.md new file mode 100644 index 00000000..3384f3d5 --- /dev/null +++ b/testnet/ev-charging-devkit/README.md @@ -0,0 +1,228 @@ +# EV Charging Devkit + +Goal of this devkit is to enable a developer to test round trip Beckn v2.0 mock messages for **EV charging flows** between network actors (BAP - EV Driver App/Charging Finder, BPP - Charging Station Operator) on their local machine within a few minutes. + +This devkit supports: +- **Charging station discovery**: Search and filter charging stations by location, connector type, power rating, and availability +- **Reservation and booking**: Reserve charging slots with time-based and quantity-based options +- **Charging session management**: Initiate, monitor, and complete charging sessions with real-time status updates +- **Payment and billing**: Handle pricing, tariffs, buyer finder fees, and transaction settlement +- **Support and cancellation**: Request support, cancel reservations, and handle dispute resolution + +It is a *batteries included* sandbox environment that requires minimal setup, with environment variables and registry connections pre-configured. + +## Prerequisites + +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) & run it in background +2. Install [Git](https://git-scm.com/downloads) and ensure it's added to your system path +3. Install [Postman](https://www.postman.com/downloads/) + +## Setup + +1. Clone this repository and navigate to the install directory: + +```bash +git clone https://github.com/Beckn-One/DEG.git +cd DEG/testnet/ev-charging-devkit/install +``` + +2. Start the containers: + +```bash +docker compose -f ./docker-compose-adapter-ev.yml up -d +docker ps +``` + +Verify the following containers are running: +- `redis` +- `onix-bap` +- `onix-bpp` +- `sandbox-bap` +- `sandbox-bpp` + +3. Open Postman and import the folder `DEG/testnet/ev-charging-devkit/postman` to import all collections. + +## Testing the EV Charging Flow + +### BAP Collection (EV Driver App initiating charging) + +Use the `ev-charging:BAP-DEG` collection: + +1. **discover** - Discover available charging stations + - `time-based-ev-charging-slot-discover` - Discover stations with spatial and filter criteria + +2. **select** - Select a charging station and options + - `time-based-ev-charging-slot-select` - Select station with quantity and fulfillment mode + +3. **init** - Initialize charging session + - `init-request` - Initialize with payment and billing details + +4. **confirm** - Confirm the charging reservation/session + - `confirm-request` - Confirm reservation with authorization + +5. **status** - Check charging session status + - `status-request` - Query current session status + +6. **update** - Update charging session (extend, modify) + - `update-request` - Update session parameters + +7. **cancel** - Cancel charging session + - `cancel-request` - Cancel reservation or ongoing session + +8. **rating** - Rate the charging service + - `rating-request` - Submit rating and feedback + +9. **support** - Request support + - `support-request` - Request assistance for issues + +### BPP Collection (Charging Station Operator responding) + +Use the `ev-charging:BPP-DEG` collection: + +1. **on_discover** - Respond to discovery requests + - `time-based-ev-charging-slot-catalog` - Return catalog of available charging stations + +2. **on_select** - Respond to selection requests + - `time-based-ev-charging-slot-on-select` - Confirm selection with pricing + +3. **on_init** - Respond to initialization requests + - `on-init-response` - Acknowledge initialization + +4. **on_confirm** - Respond to confirmation requests + - `on-confirm-response` - Confirm reservation/session start + +5. **on_status** - Respond to status queries + - `on-status-response` - Provide current session status + +6. **on_update** - Respond to update requests + - `on-update-response` - Confirm session updates + +7. **on_cancel** - Respond to cancellation requests + - `on-cancel-response` - Confirm cancellation + +8. **on_rating** - Respond to rating submissions + - `on-rating-response` - Acknowledge rating + +9. **on_support** - Respond to support requests + - `on-support-response` - Provide support information + +## Viewing Responses + +The request responses will show an "Ack" message. Detailed `on_*` messages from BPP should be visible in the BAP logs: + +```bash +docker logs -f onix-bap +``` + +## Stopping the Environment + +```bash +docker compose -f ./docker-compose-adapter-ev.yml down +``` + +## Configuration + +### Environment Variables (Pre-configured in Postman collections) + +| Variable Name | Value | Notes | +| :---------------- | :-------------------------------------- | :-------------- | +| `domain` | `beckn.one:deg:ev-charging:2.0.0` | | +| `version` | `2.0.0` | | +| `bap_id` | `ev-charging.sandbox1.com` | | +| `bap_uri` | `http://onix-bap:8081/bap/receiver` | | +| `bpp_id` | `ev-charging.sandbox2.com` | | +| `bpp_uri` | `http://onix-bpp:8082/bpp/receiver` | | +| `bap_adapter_url` | `http://localhost:8081/bap/caller` | BAP collection | +| `bpp_adapter_url` | `http://localhost:8082/bpp/caller` | BPP collection | +| `transaction_id` | Auto-generated UUID | | +| `iso_date` | Auto-generated ISO timestamp | | + +### Registry Configuration + +This devkit reuses the DeDi registry records from other DEG devkits: +- BAP: `ev-charging.sandbox1.com` (unique keys for this domain) +- BPP: `ev-charging.sandbox2.com` (unique keys for this domain) + +The test registry service is accessed at `https://api.dev.beckn.io/registry/dedi`. + +## EV Charging Flow Overview + +``` +┌─────────────────┐ ┌─────────────────┐ +│ EV Driver App │ │ Charging Station │ +│ (BAP) │ │ Operator │ +│ │ │ (BPP) │ +└────────┬────────┘ └────────┬────────┘ + │ │ + │ /discover (location, filters) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_discover (station catalog) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /select (station choice, quantity) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_select (pricing, confirmation) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /init (payment details) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_init (ack) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /confirm (authorization) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_confirm (session start) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /status (polling) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_status (progress updates) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /update (modify session) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_update (confirmation) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /cancel (if needed) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_cancel (refund/confirmation) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /rating (feedback) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_rating (ack) │ + │◄───────────────────────────────────────────────│ +``` + +## Troubleshooting + +- **Container fails to start with schema error**: You may have a stale `fidedocker/onix-adapter` image. Pull the latest: + ```bash + docker pull fidedocker/onix-adapter + ``` + +- **Registry lookup fails**: Ensure you have internet connectivity to `api.testnet.beckn.one`. + +- **Sandbox health check fails**: Wait a few seconds for the sandbox containers to initialize, then check logs: + ```bash + docker logs sandbox-bap + docker logs sandbox-bpp + ``` + +## Regenerating Postman Collection + +To regenerate the Postman collections for this devkit: + +```bash +python3 scripts/generate_postman_collection.py --devkit ev-charging --role BAP --output-dir testnet/ev-charging-devkit/postman +python3 scripts/generate_postman_collection.py --devkit ev-charging --role BPP --output-dir testnet/ev-charging-devkit/postman +``` \ No newline at end of file diff --git a/testnet/ev-charging-devkit/config/local-ev-bap.yaml b/testnet/ev-charging-devkit/config/local-ev-bap.yaml index c175a322..78049d84 100644 --- a/testnet/ev-charging-devkit/config/local-ev-bap.yaml +++ b/testnet/ev-charging-devkit/config/local-ev-bap.yaml @@ -49,6 +49,11 @@ modules: type: url location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" cache: id: cache config: @@ -101,6 +106,11 @@ modules: type: url location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" cache: id: cache config: diff --git a/testnet/ev-charging-devkit/config/local-ev-bpp.yaml b/testnet/ev-charging-devkit/config/local-ev-bpp.yaml index f54f2c5b..dd7037e8 100644 --- a/testnet/ev-charging-devkit/config/local-ev-bpp.yaml +++ b/testnet/ev-charging-devkit/config/local-ev-bpp.yaml @@ -49,6 +49,11 @@ modules: type: url location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" cache: id: cache config: @@ -96,6 +101,11 @@ modules: type: url location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" cache: id: cache config: diff --git a/testnet/ev-charging-devkit/config/local-ev-routing-BAPCaller.yaml b/testnet/ev-charging-devkit/config/local-ev-routing-BAPCaller.yaml index 1726cc4c..05c582e2 100644 --- a/testnet/ev-charging-devkit/config/local-ev-routing-BAPCaller.yaml +++ b/testnet/ev-charging-devkit/config/local-ev-routing-BAPCaller.yaml @@ -17,6 +17,6 @@ routingRules: version: "2.0.0" targetType: "url" target: # URL of Catalog Discovery Service - url: "https://FILL_ME_CATALOG_DISCOVERY_SERVICE_URL/beckn" + url: "https://34.93.141.21.sslip.io/beckn" #test CDS URL endpoints: - discover diff --git a/testnet/ev-charging-devkit/config/local-ev-routing-BPPCaller.yaml b/testnet/ev-charging-devkit/config/local-ev-routing-BPPCaller.yaml index cfa2f6de..fdf072ad 100644 --- a/testnet/ev-charging-devkit/config/local-ev-routing-BPPCaller.yaml +++ b/testnet/ev-charging-devkit/config/local-ev-routing-BPPCaller.yaml @@ -11,4 +11,11 @@ routingRules: - on_confirm - on_track - on_rating - - on_support \ No newline at end of file + - on_support + + - version: "2.0.0" + targetType: "url" + target: + url: "https://34.93.141.21.sslip.io/beckn/v2/catalog" + endpoints: + - publish diff --git a/testnet/p2p-enrollment-devkit/README.md b/testnet/p2p-enrollment-devkit/README.md new file mode 100644 index 00000000..ed6cd5fc --- /dev/null +++ b/testnet/p2p-enrollment-devkit/README.md @@ -0,0 +1,168 @@ +# P2P Enrollment Devkit + +Goal of this devkit is to enable a developer to test round trip Beckn v2.0 mock messages for **user enrollment flows** between network actors (BAP - Utility Portal, BPP - Program Owner) on their local machine within a few minutes. + +This devkit supports: +- **OTP-based enrollment**: User authenticates via mobile OTP +- **OAuth2/OIDC-based enrollment**: User authenticates via utility's OAuth2 provider + +It is a *batteries included* sandbox environment that requires minimal setup, with environment variables and registry connections pre-configured. + +## Prerequisites + +1. Install [Docker Desktop](https://www.docker.com/products/docker-desktop) & run it in background +2. Install [Git](https://git-scm.com/downloads) and ensure it's added to your system path +3. Install [Postman](https://www.postman.com/downloads/) + +## Setup + +1. Clone this repository and navigate to the install directory: + +```bash +git clone -b p2p-trading https://github.com/Beckn-One/DEG.git +cd DEG/testnet/p2p-enrollment-devkit/install +``` + +2. Start the containers: + +```bash +docker compose -f ./docker-compose-adapter-enrollment.yml up -d +docker ps +``` + +Verify the following containers are running: +- `redis-enrollment` +- `onix-enrollment-bap` +- `onix-enrollment-bpp` +- `sandbox-enrollment-bap` +- `sandbox-enrollment-bpp` + +3. Open Postman and import the folder `DEG/testnet/p2p-enrollment-devkit/postman` to import all collections. + +## Testing the Enrollment Flow + +### BAP Collection (Utility Portal initiating enrollment) + +Use the `p2p-enrollment:BAP-DEG` collection: + +1. **init** - Initiate enrollment with user authentication + - `init-request-otp` - Start OTP-based enrollment (sends mobile number) + - `init-request-oauth2` - Start OAuth2-based enrollment (sends tokens) + - `init-request-simple-consumer` - Simple consumer enrollment + - `init-request-prosumer-solar-battery` - Prosumer with DER enrollment + +2. **confirm** - Confirm enrollment with meter selection + - `confirm-request-otp` - Confirm OTP enrollment with OTP verification and meter selection + - `confirm-request-oauth2` - Confirm OAuth2 enrollment with meter selection + - `confirm-request` - Standard confirm with credentials + +3. **update** - Update enrollment + - `update-request-consent-revocation` - Revoke consent + - `update-request-unenrollment` - Unenroll from program + +### BPP Collection (Program Owner responding) + +Use the `p2p-enrollment:BPP-DEG` collection: + +1. **on_init** - Respond to init requests + - `on-init-response-otp` - Return NGUID for OTP verification + - `on-init-response-oauth2` - Return verified status with available meters + - `on-init-response-success` - Successful verification + - `on-init-response-conflict` - Enrollment conflict detected + - `on-init-response-error` - Error response + +2. **on_confirm** - Respond to confirm requests + - `on-confirm-response-otp` - OTP enrollment success with credentials + - `on-confirm-response-oauth2` - OAuth2 enrollment success + - `on-confirm-response-success` - Standard success with credential + - `on-confirm-response-no-meter` - Error: no meter specified + +3. **on_update** - Respond to update requests + - `on-update-response-consent-revocation` - Consent revoked + - `on-update-response-unenrollment` - Unenrollment confirmed + +## Viewing Responses + +The request responses will show an "Ack" message. Detailed `on_init`, `on_confirm`, `on_update` messages from BPP should be visible in the BAP logs: + +```bash +docker logs -f onix-enrollment-bap +``` + +## Stopping the Environment + +```bash +docker compose -f ./docker-compose-adapter-enrollment.yml down +``` + +## Configuration + +### Environment Variables (Pre-configured in Postman collections) + +| Variable Name | Value | Notes | +| :---------------- | :-------------------------------------- | :-------------- | +| `domain` | `beckn.one:deg:p2p-enrollment:2.0.0` | | +| `version` | `2.0.0` | | +| `bap_id` | `p2p-enrollment-sandbox1.com` | | +| `bap_uri` | `http://onix-bap:8081/bap/receiver` | | +| `bpp_id` | `p2p-enrollment-sandbox2.com` | | +| `bpp_uri` | `http://onix-bpp:8082/bpp/receiver` | | +| `bap_adapter_url` | `http://localhost:8081/bap/caller` | BAP collection | +| `bpp_adapter_url` | `http://localhost:8082/bpp/caller` | BPP collection | +| `transaction_id` | Auto-generated UUID | | +| `iso_date` | Auto-generated ISO timestamp | | + +### Registry Configuration + +This devkit reuses the DeDi registry records from the P2P Trading devkit: +- BAP: `p2p-trading-sandbox1.com` (same keys, different domain) +- BPP: `p2p-trading-sandbox2.com` (same keys, different domain) + +The registry service is accessed at `https://api.dev.beckn.io/registry/dedi`. + +## Enrollment Flow Overview + +``` +┌─────────────────┐ ┌─────────────────┐ +│ Utility Portal │ │ Program Owner │ +│ (BAP) │ │ (BPP) │ +└────────┬────────┘ └────────┬────────┘ + │ │ + │ /init (mobile for OTP or tokens for OAuth2) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_init (nguid for OTP or meters for OAuth2) │ + │◄───────────────────────────────────────────────│ + │ │ + │ /confirm (OTP + meters or tokens + meters) │ + │───────────────────────────────────────────────►│ + │ │ + │ /on_confirm (enrollment credential + status) │ + │◄───────────────────────────────────────────────│ + │ │ +``` + +## Troubleshooting + +- **Container fails to start with schema error**: You may have a stale `fidedocker/onix-adapter` image. Pull the latest: + ```bash + docker pull fidedocker/onix-adapter + ``` + +- **Registry lookup fails**: Ensure you have internet connectivity to `api.testnet.beckn.one`. + +- **Sandbox health check fails**: Wait a few seconds for the sandbox containers to initialize, then check logs: + ```bash + docker logs sandbox-enrollment-bap + docker logs sandbox-enrollment-bpp + ``` + +## Regenerating Postman Collection + +To regenerate the Postman collections for this devkit: + +```bash +python3 scripts/generate_postman_collection.py --devkit p2p-enrollment --role BAP --output-dir testnet/p2p-enrollment-devkit/postman +python3 scripts/generate_postman_collection.py --devkit p2p-enrollment --role BPP --output-dir testnet/p2p-enrollment-devkit/postman +``` + diff --git a/testnet/p2p-enrollment-devkit/config/local-enrollment-bap.yaml b/testnet/p2p-enrollment-devkit/config/local-enrollment-bap.yaml new file mode 100644 index 00000000..6cec7f31 --- /dev/null +++ b/testnet/p2p-enrollment-devkit/config/local-enrollment-bap.yaml @@ -0,0 +1,135 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8081 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: bapTxnReceiver + path: /bap/receiver/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + # Reusing p2p-trading sandbox1 registry record for enrollment BAP + networkParticipant: p2p-trading-sandbox1.com + keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ + signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + signingPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + encrPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + encrPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-enrollment-routing-BAPReceiver.yaml + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - validateSign + - addRoute + - validateSchema + + - name: bapTxnCaller + path: /bap/caller/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + # Reusing p2p-trading sandbox1 registry record for enrollment BAP + networkParticipant: p2p-trading-sandbox1.com + keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ + signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + signingPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + encrPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + encrPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-enrollment-routing-BAPCaller.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - addRoute + - sign + - validateSchema + diff --git a/testnet/p2p-enrollment-devkit/config/local-enrollment-bpp.yaml b/testnet/p2p-enrollment-devkit/config/local-enrollment-bpp.yaml new file mode 100644 index 00000000..89202987 --- /dev/null +++ b/testnet/p2p-enrollment-devkit/config/local-enrollment-bpp.yaml @@ -0,0 +1,129 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8082 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: bppTxnReceiver + path: /bpp/receiver/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + # Reusing p2p-trading sandbox2 registry record for enrollment BPP + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-enrollment-routing-BPPReceiver.yaml + steps: + - validateSign + - addRoute + # - validateSchema + + - name: bppTxnCaller + path: /bpp/caller/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-enrollment-routing-BPPCaller.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bpp + steps: + - addRoute + - sign + # - validateSchema + diff --git a/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BAPCaller.yaml b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BAPCaller.yaml new file mode 100644 index 00000000..21cdc525 --- /dev/null +++ b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BAPCaller.yaml @@ -0,0 +1,12 @@ +# BAP Caller routing rules +# Routes outgoing requests from BAP to BPP +routingRules: + - version: "2.0.0" + targetType: "bpp" + endpoints: + - init + - confirm + - status + - update + - cancel + diff --git a/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BAPReceiver.yaml b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BAPReceiver.yaml new file mode 100644 index 00000000..8d3d43eb --- /dev/null +++ b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BAPReceiver.yaml @@ -0,0 +1,14 @@ +# BAP Receiver routing rules +# Routes incoming responses from BPP to BAP webhook +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bap:3001/api/bap-webhook" + endpoints: + - on_init + - on_confirm + - on_status + - on_update + - on_cancel + diff --git a/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BPPCaller.yaml b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BPPCaller.yaml new file mode 100644 index 00000000..d2546ba1 --- /dev/null +++ b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BPPCaller.yaml @@ -0,0 +1,12 @@ +# BPP Caller routing rules +# Routes outgoing responses from BPP to BAP +routingRules: + - version: "2.0.0" + targetType: "bap" + endpoints: + - on_init + - on_confirm + - on_status + - on_update + - on_cancel + diff --git a/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BPPReceiver.yaml b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BPPReceiver.yaml new file mode 100644 index 00000000..342289c5 --- /dev/null +++ b/testnet/p2p-enrollment-devkit/config/local-enrollment-routing-BPPReceiver.yaml @@ -0,0 +1,14 @@ +# BPP Receiver routing rules +# Routes incoming requests from BAP to BPP webhook +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bpp:3002/api/webhook" + endpoints: + - init + - confirm + - status + - update + - cancel + diff --git a/testnet/p2p-enrollment-devkit/install/docker-compose-adapter-enrollment.yml b/testnet/p2p-enrollment-devkit/install/docker-compose-adapter-enrollment.yml new file mode 100644 index 00000000..6a1750fe --- /dev/null +++ b/testnet/p2p-enrollment-devkit/install/docker-compose-adapter-enrollment.yml @@ -0,0 +1,117 @@ +services: + # ============================================ + # Core Infrastructure Services + # ============================================ + + # Redis - Caching Service + redis: + image: redis:alpine + container_name: redis-enrollment + ports: + - "6379:6379" + networks: + - beckn_enrollment_network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + + # ============================================ + # Beckn Onix Adapters + # ============================================ + + onix-bap: + image: fidedocker/onix-adapter + container_name: onix-enrollment-bap + platform: linux/amd64 + networks: + - beckn_enrollment_network + ports: + - "8081:8081" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis-enrollment:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-enrollment-bap.yaml"] + depends_on: + redis: + condition: service_healthy + + onix-bpp: + image: fidedocker/onix-adapter + container_name: onix-enrollment-bpp + platform: linux/amd64 + networks: + - beckn_enrollment_network + ports: + - "8082:8082" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis-enrollment:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-enrollment-bpp.yaml"] + depends_on: + redis: + condition: service_healthy + + # ============================================ + # Sandbox Services (Mock BAP/BPP implementations) + # ============================================ + + sandbox-bap: + container_name: sandbox-enrollment-bap + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + environment: + - NODE_ENV=production + - PORT=3001 + ports: + - "3001:3001" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3001/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_enrollment_network + + sandbox-bpp: + container_name: sandbox-enrollment-bpp + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + environment: + - NODE_ENV=production + - PORT=3002 + - PERSONA=bpp + ports: + - "3002:3002" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3002/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_enrollment_network + +networks: + beckn_enrollment_network: + name: beckn_enrollment_network + driver: bridge + diff --git a/testnet/p2p-enrollment-devkit/postman/README.md b/testnet/p2p-enrollment-devkit/postman/README.md new file mode 100644 index 00000000..09f03e2c --- /dev/null +++ b/testnet/p2p-enrollment-devkit/postman/README.md @@ -0,0 +1,38 @@ +# P2P Enrollment Postman Collections + +## Auto-Generation + +These postman collections are auto-generated by running: + +```bash +python3 scripts/generate_postman_collection.py --devkit p2p-enrollment --output-dir testnet/p2p-enrollment-devkit/postman/ --role BAP +python3 scripts/generate_postman_collection.py --devkit p2p-enrollment --output-dir testnet/p2p-enrollment-devkit/postman/ --role BPP +``` + +## Collections + +| Collection | Description | Requests | +|------------|-------------|----------| +| `p2p-enrollment:BAP-DEG` | Utility Portal (BAP) initiating enrollment | 9 | +| `p2p-enrollment:BPP-DEG` | Program Owner (BPP) responding to enrollment | 11 | + +## Available Actions + +### BAP Collection (Utility Portal) +| Action | Examples | Description | +|--------|----------|-------------| +| `init` | `init-request-otp`, `init-request-oauth2`, `init-request-simple-consumer`, `init-request-prosumer-solar-battery` | Initialize enrollment with user authentication | +| `confirm` | `confirm-request-otp`, `confirm-request-oauth2`, `confirm-request` | Confirm enrollment with meter selection | +| `update` | `update-request-consent-revocation`, `update-request-unenrollment` | Update enrollment (revoke, unenroll) | + +### BPP Collection (Program Owner) +| Action | Examples | Description | +|--------|----------|-------------| +| `on_init` | `on-init-response-otp`, `on-init-response-oauth2`, `on-init-response-success`, `on-init-response-conflict`, `on-init-response-error` | Response to init requests | +| `on_confirm` | `on-confirm-response-otp`, `on-confirm-response-oauth2`, `on-confirm-response-success`, `on-confirm-response-no-meter` | Response to confirm requests | +| `on_update` | `on-update-response-consent-revocation`, `on-update-response-unenrollment` | Response to update requests | + +## Usage + +See the main [README.md](../README.md) for setup instructions and testing guide. + diff --git a/testnet/p2p-enrollment-devkit/postman/p2p-enrollment:BAP-DEG.postman_collection.json b/testnet/p2p-enrollment-devkit/postman/p2p-enrollment:BAP-DEG.postman_collection.json new file mode 100644 index 00000000..dfa2e6df --- /dev/null +++ b/testnet/p2p-enrollment-devkit/postman/p2p-enrollment:BAP-DEG.postman_collection.json @@ -0,0 +1,349 @@ +{ + "info": { + "_postman_id": "117bba7b-4d45-4ef6-ace8-0254f4e7406e", + "name": "p2p-enrollment:BAP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Buyer Application Platform implementing p2p-enrollment APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "cancel", + "item": [] + }, + { + "name": "confirm", + "item": [ + { + "name": "confirm-request-oauth2", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-oauth2-001\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OIDC\",\n \"accessToken\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwiYXVkIjoicHJvZ3JhbS1vd25lci1icHAiLCJpc3MiOiJodHRwczovL3V0aWxpdHktaWRwLmV4YW1wbGUuY29tIiwiaWF0IjoxNzI5MDAwMDAwLCJleHAiOjE3MjkwMDM2MDB9.signature\"\n },\n \"meters\": [\n {\n \"meterId\": \"umid-001\",\n \"meterNumber\": \"MTR-987654321\",\n \"connectionType\": \"residential\"\n }\n ],\n \"startDate\": \"2024-11-01T00:00:00Z\",\n \"endDate\": \"2025-10-31T23:59:59Z\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/confirm", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: confirm-request-oauth2" + }, + "response": [] + }, + { + "name": "confirm-request-otp", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-otp-001\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"pending-verification\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OTP\",\n \"mobile\": \"+919999999999\",\n \"nguid\": \"LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm\",\n \"otp\": \"123456\",\n \"utilityCustomerId\": \"CUST-123456\",\n \"userType\": \"CONSUMER\"\n },\n \"meters\": [\n {\n \"meterId\": \"umid-001\",\n \"meterNumber\": \"MTR-987654321\",\n \"connectionType\": \"residential\"\n }\n ],\n \"startDate\": \"2024-11-01T00:00:00Z\",\n \"endDate\": \"2025-10-31T23:59:59Z\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/confirm", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: confirm-request-otp" + }, + "response": [] + }, + { + "name": "confirm-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"startDate\": \"2024-11-01T00:00:00Z\",\n \"endDate\": \"2025-10-31T23:59:59Z\",\n \"consents\": [\n {\n \"type\": \"DATA_COLLECTION\",\n \"granted\": true,\n \"grantedAt\": \"2024-10-15T10:33:00Z\",\n \"description\": \"Consent to collect and share meter data for program participation\"\n },\n {\n \"type\": \"DER_CONTROL\",\n \"granted\": false,\n \"description\": \"Consent to control DER devices for demand response (not applicable for this enrollment)\"\n }\n ]\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/confirm", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: confirm-request" + }, + "response": [] + } + ] + }, + { + "name": "discover", + "item": [] + }, + { + "name": "init", + "item": [ + { + "name": "init-request-oauth2", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-oauth2-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"pending-verification\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OIDC\",\n \"accessToken\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwiYXVkIjoicHJvZ3JhbS1vd25lci1icHAiLCJpc3MiOiJodHRwczovL3V0aWxpdHktaWRwLmV4YW1wbGUuY29tIiwiaWF0IjoxNzI5MDAwMDAwLCJleHAiOjE3MjkwMDM2MDB9.signature\",\n \"idToken\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyLTEyMzQ1IiwibmFtZSI6IlJhamVzaCBLdW1hciIsImVtYWlsIjoicmFqZXNoQGV4YW1wbGUuY29tIiwiaXNzIjoiaHR0cHM6Ly91dGlsaXR5LWlkcC5leGFtcGxlLmNvbSIsImlhdCI6MTcyOTAwMDAwMCwiZXhwIjoxNzI5MDAzNjAwfQ.signature\"\n },\n \"customer\": {\n \"name\": \"Rajesh Kumar\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: init-request-oauth2" + }, + "response": [] + }, + { + "name": "init-request-otp", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-otp-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"pending-verification\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OTP\",\n \"mobile\": \"+919999999999\",\n \"utilityCustomerId\": \"CUST-123456\",\n \"userType\": \"CONSUMER\"\n },\n \"customer\": {\n \"name\": \"Rajesh Kumar\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: init-request-otp" + }, + "response": [] + }, + { + "name": "init-request-prosumer-solar-battery", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-prosumer-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"vpp-program-p2p-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:prosumer-789\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-vpp-p2p-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-prosumer-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\",\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"meters\": [\n {\n \"meterId\": \"umid-002\",\n \"utilityId\": \"utility-example-001\"\n }\n ],\n \"ders\": [\n {\n \"derId\": \"der-solar-001\",\n \"type\": \"SOLAR_PV\",\n \"capacityValue\": 10.0,\n \"capacityUnit\": \"kW\"\n },\n {\n \"derId\": \"der-battery-001\",\n \"type\": \"BATTERY_STORAGE\",\n \"capacityValue\": 15.0,\n \"capacityUnit\": \"kWh\"\n }\n ]\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OTP\",\n \"mobile\": \"+919876543210\",\n \"userType\": \"PROSUMER\"\n },\n \"meterOwnershipCredential\": {\n \"credentialId\": \"vc-meter-ownership-002\",\n \"type\": \"MeterOwnershipCredential\",\n \"format\": \"VC-JWT\",\n \"credentialData\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...\",\n \"verificationUrl\": \"https://utility-example-001.com/verify/vc-meter-ownership-002\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: init-request-prosumer-solar-battery" + }, + "response": [] + }, + { + "name": "init-request-simple-consumer", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\",\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"customer\": {\n \"name\": \"Rajesh Kumar\",\n \"email\": \"rajesh.kumar@example.com\"\n },\n \"meters\": [\n {\n \"meterId\": \"umid-001\",\n \"utilityId\": \"utility-example-001\"\n }\n ],\n \"ders\": []\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"meterOwnershipCredential\": {\n \"credentialId\": \"vc-meter-ownership-001\",\n \"type\": \"MeterOwnershipCredential\",\n \"format\": \"VC-JWT\",\n \"credentialData\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiTWV0ZXJPd25lcnNoaXBDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6dXNlci0xMjM0NSIsIm1ldGVySWQiOiJ1bWlkLTAwMSIsInV0aWxpdHlJZCI6InV0aWxpdHktZXhhbXBsZS0wMDEiLCJvd25lcnNoaXBTdGF0dXMiOiJPV05FUiIsInZhbGlkRnJvbSI6IjIwMjQtMDEtMDFUMDA6MDA6MDBaIiwidmFsaWRVbnRpbCI6IjIwMjUtMTItMzFUMjM6NTk6NTlaIn19LCJpc3MiOiJkaWQ6ZXhhbXBsZTp1dGlsaXR5LWNyZWRlbnRpYWwtaXNzdWVyIiwiaWF0IjoxNzA0MDY3MjAwfQ.signature\",\n \"verificationUrl\": \"https://utility-example-001.com/verify/vc-meter-ownership-001\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: init-request-simple-consumer" + }, + "response": [] + } + ] + }, + { + "name": "rating", + "item": [] + }, + { + "name": "select", + "item": [] + }, + { + "name": "status", + "item": [] + }, + { + "name": "support", + "item": [] + }, + { + "name": "track", + "item": [] + }, + { + "name": "update", + "item": [ + { + "name": "update-request-consent-revocation", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"update\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"CONFIRMED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"updateType\": \"CONSENT_REVOCATION\",\n \"consentRevocation\": {\n \"consentCredentialId\": \"https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001\",\n \"consentType\": \"DATA_COLLECTION\",\n \"reason\": \"USER_REQUESTED\",\n \"revokedAt\": \"2024-11-20T14:30:00Z\",\n \"effectiveDate\": \"2024-11-20T14:30:00Z\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/update", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "update" + ] + }, + "description": "Update request: update-request-consent-revocation" + }, + "response": [] + }, + { + "name": "update-request-unenrollment", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"update\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"CONFIRMED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"updateType\": \"UNENROLLMENT\",\n \"unenrollment\": {\n \"enrollmentId\": \"enrollment-consumer-001\",\n \"reason\": \"USER_REQUESTED\",\n \"effectiveDate\": \"2024-11-20T15:00:00Z\",\n \"revokeAllConsents\": true\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/update", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "update" + ] + }, + "description": "Update request: update-request-unenrollment" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-enrollment:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-enrollment-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-enrollment-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bap_adapter_url", + "value": "http://localhost:8081/bap/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-enrollment-devkit/postman/p2p-enrollment:BPP-DEG.postman_collection.json b/testnet/p2p-enrollment-devkit/postman/p2p-enrollment:BPP-DEG.postman_collection.json new file mode 100644 index 00000000..c6b8f42c --- /dev/null +++ b/testnet/p2p-enrollment-devkit/postman/p2p-enrollment:BPP-DEG.postman_collection.json @@ -0,0 +1,403 @@ +{ + "info": { + "_postman_id": "667fc472-e084-4542-9658-bbc4ee7ae0a7", + "name": "p2p-enrollment:BPP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Buyer Provider Platform implementing p2p-enrollment APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "on_cancel", + "item": [] + }, + { + "name": "on_confirm", + "item": [ + { + "name": "on-confirm-response-no-meter", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_confirm\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-oauth2-001\",\n \"beckn:orderStatus\": \"FAILED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n }\n }\n },\n \"error\": {\n \"code\": \"BIZ_NO_METER_SPECIFIED\",\n \"message\": \"No meter specified for enrollment. Please select from available meters.\",\n \"details\": {\n \"path\": \"$.message.order.orderAttributes.meters\",\n \"availableMeters\": [\n {\n \"meterId\": \"umid-001\",\n \"meterNumber\": \"MTR-987654321\",\n \"address\": \"123 Main Street, Bangalore\",\n \"sanctionedLoad\": 5.0,\n \"connectionType\": \"residential\"\n },\n {\n \"meterId\": \"umid-002\",\n \"meterNumber\": \"MTR-987654322\",\n \"address\": \"456 Oak Avenue, Bangalore\",\n \"sanctionedLoad\": 10.0,\n \"connectionType\": \"commercial\"\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_confirm" + ] + }, + "description": "On_confirm request: on-confirm-response-no-meter" + }, + "response": [] + }, + { + "name": "on-confirm-response-oauth2", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_confirm\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-oauth2-001\",\n \"beckn:orderStatus\": \"CONFIRMED\",\n \"beckn:orderNumber\": \"ENR-2024-OAUTH-001234\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"CONFIRMED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OIDC\",\n \"verified\": true,\n \"verifiedAt\": \"2024-10-15T10:35:05Z\",\n \"subject\": \"user-12345\",\n \"issuer\": \"https://utility-idp.example.com\",\n \"message\": \"Token verified successfully\"\n },\n \"enrollmentId\": \"enrollment-oauth2-001\",\n \"status\": \"ACTIVE\",\n \"programId\": \"program-p2p-trading-001\",\n \"meters\": [\n {\n \"meterId\": \"umid-001\",\n \"meterNumber\": \"MTR-987654321\",\n \"sanctionedLoad\": 5.0,\n \"connectionType\": \"residential\"\n }\n ],\n \"startDate\": \"2024-11-01T00:00:00Z\",\n \"endDate\": \"2025-10-31T23:59:59Z\",\n \"enrolledAt\": \"2024-10-15T10:35:05Z\",\n \"loggedAt\": \"2024-10-15T10:35:05Z\",\n \"logReference\": \"log-enrollment-oauth2-001\",\n \"credential\": {\n \"credentialId\": \"vc:enrollment:oauth2-001\",\n \"type\": \"ProgramEnrollmentCredential\",\n \"format\": \"VC-JWT\",\n \"credentialUrl\": \"https://vpp-program-owner.example.com/credentials/vc:enrollment:oauth2-001\",\n \"verificationUrl\": \"https://vpp-program-owner.example.com/verify/vc:enrollment:oauth2-001\",\n \"issuedAt\": \"2024-10-15T10:35:05Z\"\n },\n \"p2pdetails\": {\n \"usertype\": \"consumer\",\n \"isp2pactive\": true,\n \"iscaactive\": false,\n \"meternumber\": \"MTR-987654321\",\n \"sdload\": \"5.0\",\n \"cuflimit\": \"10.0\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_confirm" + ] + }, + "description": "On_confirm request: on-confirm-response-oauth2" + }, + "response": [] + }, + { + "name": "on-confirm-response-otp", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_confirm\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-otp-001\",\n \"beckn:orderStatus\": \"CONFIRMED\",\n \"beckn:orderNumber\": \"ENR-2024-OTP-001234\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"CONFIRMED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OTP\",\n \"verified\": true,\n \"verifiedAt\": \"2024-10-15T10:33:05Z\",\n \"message\": \"OTP verification successful\",\n \"utilityCustomerId\": \"CUST-123456\"\n },\n \"enrollmentId\": \"enrollment-otp-001\",\n \"status\": \"ACTIVE\",\n \"programId\": \"program-p2p-trading-001\",\n \"meters\": [\n {\n \"meterId\": \"umid-001\",\n \"meterNumber\": \"MTR-987654321\",\n \"sanctionedLoad\": 5.0,\n \"connectionType\": \"residential\"\n }\n ],\n \"startDate\": \"2024-11-01T00:00:00Z\",\n \"endDate\": \"2025-10-31T23:59:59Z\",\n \"enrolledAt\": \"2024-10-15T10:33:05Z\",\n \"loggedAt\": \"2024-10-15T10:33:05Z\",\n \"logReference\": \"log-enrollment-otp-001\",\n \"credential\": {\n \"credentialId\": \"vc:enrollment:otp-001\",\n \"type\": \"ProgramEnrollmentCredential\",\n \"format\": \"VC-JWT\",\n \"credentialUrl\": \"https://vpp-program-owner.example.com/credentials/vc:enrollment:otp-001\",\n \"verificationUrl\": \"https://vpp-program-owner.example.com/verify/vc:enrollment:otp-001\",\n \"issuedAt\": \"2024-10-15T10:33:05Z\"\n },\n \"p2pdetails\": {\n \"usertype\": \"prosumer\",\n \"isp2pactive\": true,\n \"iscaactive\": false,\n \"meternumber\": \"MTR-987654321\",\n \"sdload\": \"5.0\",\n \"cuflimit\": \"10.0\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_confirm" + ] + }, + "description": "On_confirm request: on-confirm-response-otp" + }, + "response": [] + }, + { + "name": "on-confirm-response-success", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_confirm\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"CONFIRMED\",\n \"beckn:orderNumber\": \"ENR-2024-001234\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"CONFIRMED\",\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"credential\": {\n \"credentialId\": \"vc:enrollment:consumer-001\",\n \"type\": \"ProgramEnrollmentCredential\",\n \"format\": \"VC-JWT\",\n \"credentialUrl\": \"https://vpp-program-owner.example.com/credentials/vc:enrollment:consumer-001\",\n \"verificationUrl\": \"https://vpp-program-owner.example.com/verify/vc:enrollment:consumer-001\",\n \"issuedAt\": \"2024-10-15T10:35:05Z\",\n \"credentialData\": \"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiUHJvZ3JhbUVucm9sbG1lbnRDcmVkZW50aWFsIl0sImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmV4YW1wbGU6dXNlci0xMjM0NSIsImVucm9sbG1lbnRJZCI6ImVucm9sbG1lbnQtY29uc3VtZXItMDAxIiwicHJvZ3JhbUlkIjoicHJvZ3JhbS1mbGV4LWRlbWFuZC1yZXNwb25zZS0wMDEiLCJtZXRlcnMiOlsidW1pZC0wMDEiXSwic3RhdHVzIjoiQUNUSVZFIiwic3RhcnREYXRlIjoiMjAyNC0xMS0wMVQwMDowMDowMFoiLCJlbmREYXRlIjoiMjAyNS0xMC0zMVQyMzo1OTo1OVoifSwiaXNzdWFuY2VEYXRlIjoiMjAyNC0xMC0xNVQxMDozNTowNVoiLCJleHBpcmF0aW9uRGF0ZSI6IjIwMjUtMTAtMzFUMjM6NTk6NTlaIn0sImlzcyI6ImRpZDpleGFtcGxlOnZwcC1wcm9ncmFtLW93bmVyIiwiaWF0IjoxNzI5MDk3NzA1fQ.signature\"\n }\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"enrollmentId\": \"enrollment-consumer-001\",\n \"status\": \"ACTIVE\",\n \"programId\": \"program-flex-demand-response-001\",\n \"startDate\": \"2024-11-01T00:00:00Z\",\n \"endDate\": \"2025-10-31T23:59:59Z\",\n \"enrolledAt\": \"2024-10-15T10:35:05Z\",\n \"loggedAt\": \"2024-10-15T10:35:05Z\",\n \"logReference\": \"log-enrollment-consumer-001\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_confirm" + ] + }, + "description": "On_confirm request: on-confirm-response-success" + }, + "response": [] + } + ] + }, + { + "name": "on_discover", + "item": [] + }, + { + "name": "on_init", + "item": [ + { + "name": "on-init-response-conflict", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-conflict-001\",\n \"beckn:orderStatus\": \"REJECTED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"credentialVerification\": {\n \"status\": \"VERIFIED\"\n },\n \"conflictCheck\": {\n \"hasConflict\": true,\n \"conflictingEnrollments\": [\n {\n \"enrollmentId\": \"enrollment-existing-001\",\n \"programId\": \"program-flex-other-001\",\n \"conflictReason\": \"Meter umid-001 is already enrolled in program-flex-other-001 from 2024-09-01 to 2025-09-01\",\n \"conflictType\": \"METER_ALREADY_ENROLLED\"\n }\n ],\n \"checkedAt\": \"2024-10-15T10:30:05Z\"\n }\n }\n }\n },\n \"error\": {\n \"code\": \"BIZ_ENROLLMENT_CONFLICT\",\n \"message\": \"Enrollment conflicts with existing enrollment. Meter umid-001 is already enrolled in another program.\",\n \"details\": {\n \"path\": \"$.message.order.orderAttributes.conflictCheck\",\n \"conflictingEnrollmentId\": \"enrollment-existing-001\",\n \"conflictEndDate\": \"2025-09-01T00:00:00Z\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_init" + ] + }, + "description": "On_init request: on-init-response-conflict" + }, + "response": [] + }, + { + "name": "on-init-response-error", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-error-001\",\n \"beckn:orderStatus\": \"REJECTED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"pending-verification\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n }\n }\n },\n \"error\": {\n \"code\": \"SEC_CREDENTIAL_VERIFICATION_FAILED\",\n \"message\": \"Meter ownership credential could not be verified\",\n \"details\": {\n \"path\": \"$.message.order.orderAttributes.meterOwnershipCredential\",\n \"credentialId\": \"vc-meter-ownership-001\",\n \"reason\": \"Invalid signature or expired credential\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_init" + ] + }, + "description": "On_init request: on-init-response-error" + }, + "response": [] + }, + { + "name": "on-init-response-oauth2", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-oauth2-001\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OIDC\",\n \"verified\": true,\n \"verifiedAt\": \"2024-10-15T10:30:05Z\",\n \"subject\": \"user-12345\",\n \"issuer\": \"https://utility-idp.example.com\",\n \"scope\": \"openid profile email meter:read\",\n \"expiresAt\": \"2024-10-15T11:30:00Z\",\n \"message\": \"Token verified successfully\"\n },\n \"meters\": [\n {\n \"meterId\": \"umid-001\",\n \"meterNumber\": \"MTR-987654321\",\n \"sanctionedLoad\": 5.0,\n \"connectionType\": \"residential\",\n \"utilityId\": \"utility-example-001\"\n },\n {\n \"meterId\": \"umid-002\",\n \"meterNumber\": \"MTR-987654322\",\n \"sanctionedLoad\": 10.0,\n \"connectionType\": \"commercial\",\n \"utilityId\": \"utility-example-001\"\n }\n ],\n \"requiredConsents\": [\n {\n \"type\": \"DATA_COLLECTION\",\n \"description\": \"Consent to collect and share meter data for program participation\",\n \"required\": true\n },\n {\n \"type\": \"DER_CONTROL\",\n \"description\": \"Consent to control DER devices for demand response (if applicable)\",\n \"required\": false\n }\n ]\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_init" + ] + }, + "description": "On_init request: on-init-response-oauth2" + }, + "response": [] + }, + { + "name": "on-init-response-otp", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-otp-001\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"pending-verification\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-p2p-trading-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"userAuth\": {\n \"authMethod\": \"OTP\",\n \"nguid\": \"LQUejkRbBL9nJGQiqbComfQ242AHnbG3hnwWdHJut59jqmdJygnVHoiyDcnAUrKm\",\n \"message\": \"OTP sent to +91XXXXXX9999. Valid for 5 minutes.\",\n \"expiresAt\": \"2024-10-15T10:35:00Z\",\n \"utilityCustomerId\": \"CUST-123456\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_init" + ] + }, + "description": "On_init request: on-init-response-otp" + }, + "response": [] + }, + { + "name": "on-init-response-success", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"PENDING\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"credentialVerification\": {\n \"status\": \"VERIFIED\",\n \"verifiedCredentials\": [\n {\n \"credentialId\": \"vc-meter-ownership-001\",\n \"status\": \"VERIFIED\",\n \"verifiedAt\": \"2024-10-15T10:30:05Z\"\n },\n {\n \"credentialId\": \"vc-program-eligibility-001\",\n \"status\": \"VERIFIED\",\n \"verifiedAt\": \"2024-10-15T10:30:05Z\"\n }\n ]\n },\n \"conflictCheck\": {\n \"hasConflict\": false,\n \"checkedAt\": \"2024-10-15T10:30:05Z\",\n \"message\": \"No conflicts found with existing enrollments\"\n },\n \"requiredCredentials\": [\n {\n \"type\": \"MeterOwnershipCredential\",\n \"description\": \"Proof of meter ownership verified through utility OTP verification\",\n \"status\": \"PROVIDED\"\n },\n {\n \"type\": \"ProgramEligibilityCredential\",\n \"description\": \"Proof of program eligibility based on meter type and location\",\n \"status\": \"PROVIDED\"\n }\n ],\n \"requiredConsents\": [\n {\n \"type\": \"DATA_COLLECTION\",\n \"description\": \"Consent to collect and share meter data for program participation\",\n \"required\": true\n },\n {\n \"type\": \"DER_CONTROL\",\n \"description\": \"Consent to control DER devices for demand response (if applicable)\",\n \"required\": false\n },\n {\n \"type\": \"CROSS_UTILITY_SHARING\",\n \"description\": \"Consent to share data across utilities (if applicable)\",\n \"required\": false\n }\n ]\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_init" + ] + }, + "description": "On_init request: on-init-response-success" + }, + "response": [] + } + ] + }, + { + "name": "on_rating", + "item": [] + }, + { + "name": "on_select", + "item": [] + }, + { + "name": "on_status", + "item": [] + }, + { + "name": "on_support", + "item": [] + }, + { + "name": "on_track", + "item": [] + }, + { + "name": "on_update", + "item": [ + { + "name": "on-update-response-consent-revocation", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_update\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"CONFIRMED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"CONFIRMED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"enrollmentId\": \"enrollment-consumer-001\",\n \"status\": \"ACTIVE\",\n \"updateType\": \"CONSENT_REVOCATION\",\n \"consentRevocation\": {\n \"consentCredentialId\": \"https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001\",\n \"status\": \"REVOKED\",\n \"revokedAt\": \"2024-11-20T14:30:05Z\",\n \"statusListUrl\": \"https://vpp-program-owner.example.com/status/consent-list\",\n \"statusListIndex\": \"94567\",\n \"message\": \"Consent has been revoked and added to revocation status list. Future verifications will fail.\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_update", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_update" + ] + }, + "description": "On_update request: on-update-response-consent-revocation" + }, + "response": [] + }, + { + "name": "on-update-response-unenrollment", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_update\",\n \"domain\": \"{{domain}}\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-onboard-consumer-001\",\n \"beckn:orderStatus\": \"CANCELLED\",\n \"beckn:seller\": \"vpp-program-flex-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"did:example:user-12345\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"program-flex-demand-response-001\"\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-onboard-001\",\n \"beckn:mode\": \"DIGITAL\",\n \"beckn:fulfillmentStatus\": \"CANCELLED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/p2p-trading/schema/EnergyEnrollment/v0.2/context.jsonld\",\n \"@type\": \"EnergyEnrollment\",\n \"enrollmentId\": \"enrollment-consumer-001\",\n \"status\": \"CANCELLED\",\n \"updateType\": \"UNENROLLMENT\",\n \"unenrollment\": {\n \"enrollmentId\": \"enrollment-consumer-001\",\n \"status\": \"CANCELLED\",\n \"cancelledAt\": \"2024-11-20T15:00:05Z\",\n \"enrollmentCredentialStatus\": {\n \"statusListUrl\": \"https://vpp-program-owner.example.com/status/enrollment-list\",\n \"statusListIndex\": \"12345\",\n \"revoked\": true\n },\n \"consentsRevoked\": [\n {\n \"consentCredentialId\": \"https://vpp-program-owner.example.com/credentials/vc:consent:consumer-001\",\n \"statusListUrl\": \"https://vpp-program-owner.example.com/status/consent-list\",\n \"statusListIndex\": \"94567\",\n \"revoked\": true\n }\n ],\n \"message\": \"Enrollment and all associated consents have been revoked. Enrollment credential and consent credentials have been added to revocation status lists.\"\n },\n \"loggedAt\": \"2024-11-20T15:00:05Z\",\n \"logReference\": \"log-unenrollment-consumer-001\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_update", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_update" + ] + }, + "description": "On_update request: on-update-response-unenrollment" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-enrollment:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-enrollment-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-enrollment-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bpp_adapter_url", + "value": "http://localhost:8082/bpp/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-devkit/README.md b/testnet/p2p-trading-devkit/README.md new file mode 100644 index 00000000..20ccb536 --- /dev/null +++ b/testnet/p2p-trading-devkit/README.md @@ -0,0 +1,156 @@ +# P2P Energy Trading Devkit + +Goal of this devkit is to enable a developer to test round trip Beckn v2.0 mock messages between all network actors (BAP, Prosumer BPP (called BPP for brevity), Utility BPP, see [implementation-guide](/docs/implementation-guides/v2/P2P_Trading/P2P_Trading_implementation_guide_DRAFT.md)), on their local machine within a few minutes. + +It is a *batteries included* sandbox environment that requires minimal setup, and has environment variables pre-configured, connections to Catalog Discovery Service and Dedi test registry service pre-configured. + +## Setup + +1. Install [docker desktop](https://www.docker.com/products/docker-desktop) & run it in background. +2. Install [git](https://git-scm.com/downloads) ensure that git is added to your system path. +3. Install [postman](https://www.postman.com/downloads/) +4. Clone this repository using git command line interface and navigate to the install directory. (TODO: branch p2p-trading needs to be removed after merge to main from the following command) + +``` +git clone -b p2p-trading https://github.com/Beckn-One/DEG.git +cd DEG/testnet/p2p-energy-trading-devkit/install +``` + +### References used in this guide +- Beckn 2.0 sandbox [repo](https://github.com/beckn/sandbox), [image](https://hub.docker.com/r/fidedocker/sandbox-2.0). +- Beckn-Onix [repo](https://github.com/Beckn-One/beckn-onix), [image](https://hub.docker.com/r/fidedocker/onix-adapter). +- DeDi (decentralized directory, a Beckn-One service based open DeDi [protocol](https://github.com/finternet-io/dedi)) website [production](https://dedi.global/), [test](https://publish-test.dedi.global/). We use test DeDi server for this demo. +- Registry service (cache layer on top of DeDi, a Beckn-One service) [production](https://api.beckn.io/registry), [test](http://api.dev.beckn.io/registry). We use test registry server for this demo. + + +## Test network + +1. Spin up the containers using docker compose. Verify that the following containers are running: redis, onix-bap, onix-bpp, onix-utilitybpp, sandbox-bap, sandbox-bpp, sandbox-utilitybpp. You can also navigate to docker desktop and check the containers and their logs. + ``` + docker compose -f ./docker-compose-adapter-p2p.yml up -d --build + docker ps + ``` + +2. Open postman and import the folder `DEG/testnet/p2p-energy-trading-devkit/postman` to import all the collections and environment variables. + +3. Start by publishing a mock catalog to the catalog discovery service using the collection `P2P-Trading:CDSupload-DEG`. + +4. Check if you can see this catalog via a BAP by using the collection `P2P-Trading:BAP-DEG/discover`. Note that this can be flaky and may timeout sometimes due to CDS unavailability. In that case try again. + +5. Use the collection `P2P-Trading:BAP-DEG` (select, init, confirm, status queries) to test the round trip Beckn v2.0 mock messages between BAP and BPP. The query reponse will show an "Ack" message, and detailed `on_select`, `on_init`, `on_confirm`, `on_status` messages from BPP should be visible in the BAP logs. + +6. Use the collection `P2P-Trading:BPP-DEG` (on_select, on_init, on_confirm, on_status) to test only the BPP to BAP trip Beckn v2.0 mock messages between BPP to BAP. + +7. Use the collection `P2P-Trading:BPP-DEG` (cascaded_init) to test only the BPP to Utility BPP round trip Beckn v2.0 mock messages. The query reponse will show an "Ack" message, and detailed `on_init`, `on_confirm`, `on_status` messages from Utility BPP should be visible in the Prosumer BPP logs. + +8. Use the collection `P2P-Trading:UtilityBPP-DEG` (cascaded_init) to test only the Utility BPP to prosumer BPP Beckn v2.0 mock messages. The query reponse will show an "Ack" message, and detailed `on_init`, `on_confirm`, `on_status` messages from Utility BPP should be visible in the Prosumer BPP logs. + +9. Stop the containers using docker compose + ``` + docker compose -f ./docker-compose-adapter-p2p.yml down + ``` + +## Under the hood + +1. BAP `discover` calls are routed to Catalog Discovery Service url `https://34.93.141.21.sslip.io/beckn` defined [here](./config/local-p2p-routing-BuyerBAPCaller.yaml) +2. Public keys from network participants are fetched from Beckn One registry service `http://api.dev.beckn.io/registry/dedi` which acts as a cache layer on top of Dedi registry, and are used to confirm that Beckn messages are sent by the trusted actor (and not by an imposter). The namespace and registry entries in Dedi are preconfigured in yaml files within config folder. The process of creating a DiDi namespace and registries is defined [here](https://beckn-labs.gitbook.io/beckn-labs-docs/beckn-registry/publishing-subscriber-details) and also further down on this page. For testing, it is recommended to create records in Dedi registry which are then cached by Beckn One registry service every hour. The registry records such as `p2p-trading-sandbox1.com` (BAP), `p2p-trading-sandbox2.com` (BPP), `p2p-trading-sandbox3.com` (utility BPP) were added beforehand, and used in this devkit. An example API call during runtime to registry service looks like [this](https://api.dev.beckn.io/registry/dedi/lookup/p2p-trading-sandbox1.com/subscribers.beckn.one/76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ). +3. Routing rules within each actor are defined in config for [BAP](./config/local-p2p-bap.yaml), [BPP](./config/local-p2p-bpp.yaml), [Utility BPP](./config/local-p2p-utilitybpp.yaml). +4. Network between various actors is defined in docker-compose-adapter-p2p.yml +5. Variables are preconfigured to following values. + | Variable Name | Value | Notes | + | :-------------------------- | :----------------------------------------- | :-------------------------- | + | `domain` | `beckn.one:deg:p2p-trading:2.0.0` | | + | `version` | `2.0.0` | | + | `bap_id` | `p2p-trading-sandbox1.com` | | + | `bap_uri` | `http://onix-bap:8081/bap/receiver` | | + | `bpp_id` | `p2p-trading-sandbox2.com` | | + | `bpp_uri` | `http://onix-bpp:8082/bpp/receiver` | | + | `bpp_bapreceiver_uri` | `http://onix-bpp:8082/bap/receiver` | | + | `utilitybpp_id` | `p2p-trading-sandbox3.com` | | + | `utilitybpp_uri` | `http://onix-utilitybpp:8083/bpp/receiver` | | + | `bap_adapter_url` | `http://localhost:8081/bap/caller` | BAP collection only | + | `bpp_adapter_url` | `http://localhost:8082/bpp/caller` | BPP collection only | + | `bpp_adapter_bapcaller_url` | `http://localhost:8082/bap/caller` | BPP collection only | + | `utilitybpp_adapter_url` | `http://localhost:8083/bpp/caller` | Utility BPP collection only | + | `transaction_id` | `3769776b-88b4-469d-9ee2-95044fe5dafc` | | + | `iso_date` | `2025-01-01T10:00:00Z` | | + | `cds_url` | `https://34.93.141.21.sslip.io` | CDS Upload collection only | + +## Routing + +
+P2P Routing Diagram + +![P2P Routing Diagram](./assets/p2p-routing-diagram.png) + +
+ +## Next steps towards a production network: + +TBD + +## Troubleshooting + +- If one of your onix containers fails to start due to `failed to load SchemaValidator plugin` error, + you may have an older stale image of `fidedocker/onix-adapter` [here](https://hub.docker.com/r/fidedocker/onix-adapter). + +## Setting up Dedi registry + +A more complete documentation is located [here](https://beckn-labs.gitbook.io/beckn-labs-docs/beckn-registry/publishing-subscriber-details), which also includes a [video walk-through](https://www.loom.com/share/e0293309701348dc95719a98b957d12c?sid=04b8dc00-51de-46ac-82ce-adc1a0060409). Here are just the steps taken to create a dummy registry for this testnet. + + +- Registered in the DeDi [dev website](https://publish-test.dedi.global/) and created two + unverified (verification happens when you own a fully qualified domain name, and can store a publicly viewable dedi verification file on it) namespaces. Namespaces should be one per atomic entity like an organization. Here it was created for utility and a network participant + which is both a BAP & BPP. Ideally each network participant should claim their own namespace, add registries to it, create registry records within each registry (say for their BAP and BPP). + +
+ Test dedi namespaces + + ![Test dedi namespaces](./assets/dedi-dashboard.png) + +
+- Registries created within namespace `np_subscriber_detail` are as follows. + +
+ Test network participant registries + + ![Test network participant registries](./assets/dedi-np-registry-records.png) + +
+- A specific registry record created for a participant BAP looks like below. + Note that it asks for a various fields such as `url` which is the callback url of subscriber, `type` (BAP or BPP or BG or CDS), `countries`, `subscriber_id`, `domain = 'beckn.one:deg:p2p-trading'` (globally unique FQDN of platform) and `signing_public_key`. Public and private key pairs can be generated by the utility script located [here](https://github.com/Beckn-One/beckn-onix/blob/main/install/generate-ed25519-keys.go). e.g. `go run generate-ed25519-keys.go ` + +
+ BAP sandbox 1 registry record + + ![BAP sandbox 1 registry record](./assets/dedi-np-registry-record-bap.png) + +
+- Similar registry records are created for BPP + +
+ BPP sandbox 2 registry record + + ![BPP sandbox 2 registry record](./assets/dedi-np-registry-record-bpp.png) + +
+- And another one for utility BPP. + +
+ Utility BPP sandbox 3 registry record + + ![Utility BPP sandbox 3 registry record](./assets/dedi-utility-registry-record-utilitybpp.png) + +
+- Within the beckn-onix configuration (`config/*.yaml` files) use the `networkParticipant` (`subscriber_id` from DeDi setup), `keyId` (Record ID from DeDi setup) along with the signing & encryption private and public keys. +- Finally enable caching of the DeDi registry by registry service by completeing last step from [these instructions](https://beckn-labs.gitbook.io/beckn-labs-docs/beckn-registry/publishing-subscriber-details). + +## Regenerating Postman Collection + +To regenerate the Postman collections for this devkit: + +```bash +python3 scripts/generate_postman_collection.py --devkit p2p-trading --role BAP --output-dir testnet/p2p-trading-devkit/postman +python3 scripts/generate_postman_collection.py --devkit p2p-trading --role BPP --output-dir testnet/p2p-trading-devkit/postman +python3 scripts/generate_postman_collection.py --devkit p2p-trading --role UtilityBPP --output-dir testnet/p2p-trading-devkit/postman +``` diff --git a/testnet/p2p-trading-devkit/assets/dedi-dashboard.png b/testnet/p2p-trading-devkit/assets/dedi-dashboard.png new file mode 100644 index 00000000..f3170f8e Binary files /dev/null and b/testnet/p2p-trading-devkit/assets/dedi-dashboard.png differ diff --git a/testnet/p2p-trading-devkit/assets/dedi-np-registry-record-bap.png b/testnet/p2p-trading-devkit/assets/dedi-np-registry-record-bap.png new file mode 100644 index 00000000..31069edd Binary files /dev/null and b/testnet/p2p-trading-devkit/assets/dedi-np-registry-record-bap.png differ diff --git a/testnet/p2p-trading-devkit/assets/dedi-np-registry-record-bpp.png b/testnet/p2p-trading-devkit/assets/dedi-np-registry-record-bpp.png new file mode 100644 index 00000000..dd9edf46 Binary files /dev/null and b/testnet/p2p-trading-devkit/assets/dedi-np-registry-record-bpp.png differ diff --git a/testnet/p2p-trading-devkit/assets/dedi-np-registry-records.png b/testnet/p2p-trading-devkit/assets/dedi-np-registry-records.png new file mode 100644 index 00000000..ae2cc58e Binary files /dev/null and b/testnet/p2p-trading-devkit/assets/dedi-np-registry-records.png differ diff --git a/testnet/p2p-trading-devkit/assets/dedi-utility-registry-record-utilitybpp.png b/testnet/p2p-trading-devkit/assets/dedi-utility-registry-record-utilitybpp.png new file mode 100644 index 00000000..852c4469 Binary files /dev/null and b/testnet/p2p-trading-devkit/assets/dedi-utility-registry-record-utilitybpp.png differ diff --git a/testnet/p2p-trading-devkit/assets/dedi-utility-registry-records.png b/testnet/p2p-trading-devkit/assets/dedi-utility-registry-records.png new file mode 100644 index 00000000..a28cf93e Binary files /dev/null and b/testnet/p2p-trading-devkit/assets/dedi-utility-registry-records.png differ diff --git a/testnet/p2p-trading-devkit/assets/p2p-routing-diagram.png b/testnet/p2p-trading-devkit/assets/p2p-routing-diagram.png new file mode 100644 index 00000000..b8979902 Binary files /dev/null and b/testnet/p2p-trading-devkit/assets/p2p-routing-diagram.png differ diff --git a/testnet/p2p-trading-devkit/config/local-p2p-bap.yaml b/testnet/p2p-trading-devkit/config/local-p2p-bap.yaml new file mode 100644 index 00000000..c4cb3f65 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-bap.yaml @@ -0,0 +1,132 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8081 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: bapTxnReceiver + path: /bap/receiver/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox1.com + keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ + signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + signingPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + encrPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + encrPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-BuyerBAPReceiver.yaml + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - validateSign + - addRoute + - validateSchema + + - name: bapTxnCaller + path: /bap/caller/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox1.com + keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ + signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + signingPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + encrPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + encrPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-BuyerBAPCaller.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - addRoute + - sign + - validateSchema \ No newline at end of file diff --git a/testnet/p2p-trading-devkit/config/local-p2p-bpp.yaml b/testnet/p2p-trading-devkit/config/local-p2p-bpp.yaml new file mode 100644 index 00000000..2b57f1ff --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-bpp.yaml @@ -0,0 +1,244 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8082 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: bppTxnReceiver + path: /bpp/receiver/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml + steps: + - validateSign + - addRoute + # - validateSchema + + - name: bppTxnCaller + path: /bpp/caller/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bpp + steps: + - addRoute + - sign + # - validateSchema + + # BAP Modules: For cascaded calls to utility BPP + # This module receives responses FROM utility BPP (on_init, on_confirm, on_update) + - name: bapTxnReceiver + path: /bap/receiver/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - validateSign + - addRoute + - validateSchema + + # This module sends cascaded requests TO utility BPP (init, confirm) + - name: bapTxnCaller + path: /bap/caller/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - addRoute + - sign + - validateSchema \ No newline at end of file diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-BuyerBAPCaller.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-BuyerBAPCaller.yaml new file mode 100644 index 00000000..80c82ff6 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-BuyerBAPCaller.yaml @@ -0,0 +1,20 @@ +routingRules: + - version: "2.0.0" + targetType: "bpp" + endpoints: + - select + - init + - confirm + - status + - track + - cancel + - update + - rating + - support + + - version: "2.0.0" + targetType: "url" + target: + url: "https://34.93.141.21.sslip.io/beckn" #test CDS URL + endpoints: + - discover diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-BuyerBAPReceiver.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-BuyerBAPReceiver.yaml new file mode 100644 index 00000000..7dfa0336 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-BuyerBAPReceiver.yaml @@ -0,0 +1,13 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bap:3001/api/bap-webhook" + endpoints: + - on_discover + - on_select + - on_init + - on_confirm + - on_status + - on_update + - on_cancel diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml new file mode 100644 index 00000000..dad97c19 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml @@ -0,0 +1,7 @@ +routingRules: + - version: "2.0.0" + targetType: "bpp" + endpoints: + - init + - confirm + diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml new file mode 100644 index 00000000..41e177b2 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml @@ -0,0 +1,10 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bpp:3002/api/bap-webhook" + endpoints: + - on_init + - on_confirm + - on_update + diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml new file mode 100644 index 00000000..8576bdf1 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml @@ -0,0 +1,20 @@ +routingRules: + - version: "2.0.0" + targetType: "bap" + endpoints: + - on_status + - on_cancel + - on_update + - on_select + - on_init + - on_confirm + - on_track + - on_rating + - on_support + + - version: "2.0.0" + targetType: "url" + target: + url: "https://34.93.141.21.sslip.io/beckn/catalog" + endpoints: + - publish diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml new file mode 100644 index 00000000..9a0897c9 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml @@ -0,0 +1,22 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bpp:3002/api/webhook" + endpoints: + - select + - init + - confirm + - status + - track + - cancel + - update + - rating + - support + + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bpp:3002/api/webhook" + endpoints: + - catalog/on_publish #publish response from CDS after catalog update \ No newline at end of file diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-UtilityBPPCaller.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-UtilityBPPCaller.yaml new file mode 100644 index 00000000..adc49d57 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-UtilityBPPCaller.yaml @@ -0,0 +1,9 @@ +routingRules: + - version: "2.0.0" + targetType: "bap" + endpoints: + - on_init # response to cascaded init from P2P Trading BPP + - on_confirm # response to cascaded confirm from P2P Trading BPP + - on_update # update sent to P2P Trading BPP after fulfillment + + diff --git a/testnet/p2p-trading-devkit/config/local-p2p-routing-UtilityBPPReceiver.yaml b/testnet/p2p-trading-devkit/config/local-p2p-routing-UtilityBPPReceiver.yaml new file mode 100644 index 00000000..2cae7f43 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-routing-UtilityBPPReceiver.yaml @@ -0,0 +1,10 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-utilitybpp:3003/api/webhook" + endpoints: + - init # cascaded init from P2P Trading BPP + - confirm # cascaded confirm from P2P Trading BPP + + diff --git a/testnet/p2p-trading-devkit/config/local-p2p-utilitybpp.yaml b/testnet/p2p-trading-devkit/config/local-p2p-utilitybpp.yaml new file mode 100644 index 00000000..3905b2e2 --- /dev/null +++ b/testnet/p2p-trading-devkit/config/local-p2p-utilitybpp.yaml @@ -0,0 +1,127 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8083 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: utilitybppTxnReceiver + path: /bpp/receiver/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox3.com + keyId: 76EU8cNkz3dBEVaR5THuyCciMv9FbA2QqDADHX88WPyYP4v5Cp9ADD + signingPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + signingPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + encrPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + encrPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-UtilityBPPReceiver.yaml + steps: + - validateSign + - addRoute + - validateSchema + + - name: utilitybppTxnCaller + path: /bpp/caller/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox3.com + keyId: 76EU8cNkz3dBEVaR5THuyCciMv9FbA2QqDADHX88WPyYP4v5Cp9ADD + signingPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + signingPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + encrPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + encrPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-UtilityBPPCaller.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bpp + steps: + - addRoute + - sign + - validateSchema diff --git a/testnet/p2p-trading-devkit/install/docker-compose-adapter-p2p.yml b/testnet/p2p-trading-devkit/install/docker-compose-adapter-p2p.yml new file mode 100644 index 00000000..775a86c2 --- /dev/null +++ b/testnet/p2p-trading-devkit/install/docker-compose-adapter-p2p.yml @@ -0,0 +1,149 @@ +services: + # ============================================ + # Core Infrastructure Services + # ============================================ + + # Redis - Caching Service + redis: + image: redis:alpine + container_name: redis + ports: + - "6379:6379" + networks: + - beckn_network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + + onix-bap: + image: fidedocker/onix-adapter + container_name: onix-bap + platform: linux/amd64 + networks: + - beckn_network + ports: + - "8081:8081" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-p2p-bap.yaml"] + + onix-bpp: + image: fidedocker/onix-adapter + container_name: onix-bpp + platform: linux/amd64 + networks: + - beckn_network + ports: + - "8082:8082" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-p2p-bpp.yaml"] + + onix-utilitybpp: + image: fidedocker/onix-adapter + pull_policy: never + container_name: onix-utilitybpp + platform: linux/amd64 + networks: + - beckn_network + ports: + - "8083:8083" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-p2p-utilitybpp.yaml"] + + sandbox-bap: + container_name: sandbox-bap + + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + + environment: + - NODE_ENV=production + - PORT=3001 + ports: + - "3001:3001" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3001/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_network + + sandbox-bpp: + container_name: sandbox-bpp + + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + + environment: + - NODE_ENV=production + - PORT=3002 + - PERSONA=bpp # bpp persona + ports: + - "3002:3002" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3002/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_network + + sandbox-utilitybpp: + container_name: sandbox-utilitybpp + + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + + environment: + - NODE_ENV=production + - PORT=3003 + - PERSONA=utility-bpp # utility-bpp persona + ports: + - "3003:3003" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3003/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_network + +networks: + beckn_network: + name: beckn_network + driver: bridge diff --git a/testnet/p2p-trading-devkit/postman/p2p-trading:BAP-DEG.postman_collection.json b/testnet/p2p-trading-devkit/postman/p2p-trading:BAP-DEG.postman_collection.json new file mode 100644 index 00000000..bf54f404 --- /dev/null +++ b/testnet/p2p-trading-devkit/postman/p2p-trading:BAP-DEG.postman_collection.json @@ -0,0 +1,277 @@ +{ + "info": { + "_postman_id": "1d173b57-15be-4f4d-8929-ff05bc3e3b5d", + "name": "p2p-trading:BAP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Buyer Application Platform implementing p2p-trading APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "confirm", + "item": [ + { + "name": "cascaded-confirm-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": 15.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/confirm", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: cascaded-confirm-request" + }, + "response": [] + }, + { + "name": "confirm-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": 25.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/confirm", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: confirm-request" + }, + "response": [] + } + ] + }, + { + "name": "discover", + "item": [ + { + "name": "discover-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\",\n \"location\": {\n \"city\": {\n \"code\": \"BLR\",\n \"name\": \"Bangalore\"\n },\n \"country\": {\n \"code\": \"IND\",\n \"name\": \"India\"\n }\n },\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld\"\n ]\n },\n \"message\": {\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?('p2p-trading-pilot-network' == @.beckn:networkId && @.beckn:itemAttributes.sourceType == 'SOLAR' && @.beckn:itemAttributes.deliveryMode == 'GRID_INJECTION' && @.beckn:itemAttributes.availableQuantity >= 10.0 )]\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/discover", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "discover" + ] + }, + "description": "Discover request: discover-request" + }, + "response": [] + } + ] + }, + { + "name": "init", + "item": [ + { + "name": "cascaded-init-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": 15.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: cascaded-init-request" + }, + "response": [] + }, + { + "name": "init-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": 25.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: init-request" + }, + "response": [] + } + ] + }, + { + "name": "select", + "item": [ + { + "name": "select-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"select\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": 25.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/select", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "select" + ] + }, + "description": "Select request: select-request" + }, + "response": [] + } + ] + }, + { + "name": "status", + "item": [ + { + "name": "status-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"beckn:id\": \"order-energy-001\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/status", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "status" + ] + }, + "description": "Status request: status-request" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-trading:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-trading-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-trading-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bap_adapter_url", + "value": "http://localhost:8081/bap/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-devkit/postman/p2p-trading:BPP-DEG.postman_collection.json b/testnet/p2p-trading-devkit/postman/p2p-trading:BPP-DEG.postman_collection.json new file mode 100644 index 00000000..a8f281de --- /dev/null +++ b/testnet/p2p-trading-devkit/postman/p2p-trading:BPP-DEG.postman_collection.json @@ -0,0 +1,341 @@ +{ + "info": { + "_postman_id": "14082ecf-a408-4dcc-979a-93ce7b798bce", + "name": "p2p-trading:BPP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Buyer Provider Platform implementing p2p-trading APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "on_confirm", + "item": [ + { + "name": "confirm-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": 25.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_confirm" + ] + }, + "description": "On_confirm request: confirm-response" + }, + "response": [] + } + ] + }, + { + "name": "on_discover", + "item": [ + { + "name": "discover-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_discover\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"catalogs\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Catalog\",\n \"beckn:id\": \"catalog-energy-001\",\n \"beckn:bppId\": \"bpp.energy-provider.com\",\n \"beckn:bppUri\": \"https://bpp.energy-provider.com\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Trading Catalog\"\n },\n \"beckn:items\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 30.5 kWh\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"certificationStatus\": \"Carbon Offset Certified\",\n \"meterId\": \"der://meter/100200300\",\n \"availableQuantity\": 30.5,\n \"productionWindow\": [\n {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T10:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n ],\n \"sourceVerification\": {\n \"verified\": true,\n \"verificationDate\": \"2024-09-01T00:00:00Z\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert.pdf\"\n ]\n },\n \"productionAsynchronous\": true\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer - 6am-12pm\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"wheelingCharges\": {\n \"amount\": 2.5,\n \"currency\": \"USD\",\n \"description\": \"PG&E Grid Services wheeling charge\"\n },\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T23:59:59Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer - 12pm-6pm\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"wheelingCharges\": {\n \"amount\": 2.5,\n \"currency\": \"USD\",\n \"description\": \"PG&E Grid Services wheeling charge\"\n },\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T23:59:59Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_discover", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_discover" + ] + }, + "description": "On_discover request: discover-response" + }, + "response": [] + } + ] + }, + { + "name": "on_init", + "item": [ + { + "name": "init-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": 25.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_init" + ] + }, + "description": "On_init request: init-response" + }, + "response": [] + } + ] + }, + { + "name": "on_select", + "item": [ + { + "name": "select-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_select\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": 25.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_select", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_select" + ] + }, + "description": "On_select request: select-response" + }, + "response": [] + } + ] + }, + { + "name": "on_status", + "item": [ + { + "name": "status-response-completed", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"COMPLETED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 15.0,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T09:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 7.5,\n \"allocatedEnergy\": 7.5,\n \"unit\": \"kWh\"\n },\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T09:00:00Z\",\n \"schema:endTime\": \"2024-10-04T12:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 7.5,\n \"allocatedEnergy\": 7.5,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T12:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 10.0,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T12:00:00Z\",\n \"schema:endTime\": \"2024-10-04T15:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 5.0,\n \"allocatedEnergy\": 5.0,\n \"unit\": \"kWh\"\n },\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T15:00:00Z\",\n \"schema:endTime\": \"2024-10-04T18:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 5.0,\n \"allocatedEnergy\": 5.0,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T18:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_status", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_status" + ] + }, + "description": "On_status request: status-response-completed" + }, + "response": [] + }, + { + "name": "status-response-curtailed", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"PARTIALLYFULFILLED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 10.0,\n \"curtailedQuantity\": 5.0,\n \"curtailmentReason\": \"GRID_OUTAGE\",\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T14:30:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 10.0,\n \"allocatedEnergy\": 10.0,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T14:30:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"FAILED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 0.0,\n \"curtailedQuantity\": 10.0,\n \"curtailmentReason\": \"GRID_OUTAGE\",\n \"meterReadings\": [],\n \"lastUpdated\": \"2024-10-04T14:30:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_status", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_status" + ] + }, + "description": "On_status request: status-response-curtailed" + }, + "response": [] + }, + { + "name": "status-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"IN_PROGRESS\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 7.5,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T09:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 7.5,\n \"allocatedEnergy\": 7.5,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T15:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"PENDING\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 0.0,\n \"meterReadings\": [],\n \"lastUpdated\": \"2024-10-04T15:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-afternoon-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.18,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_status", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_status" + ] + }, + "description": "On_status request: status-response" + }, + "response": [] + } + ] + }, + { + "name": "on_update", + "item": [ + { + "name": "on-update-response-curtailment", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_update\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"INPROGRESS\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"IN_PROGRESS\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 8.5,\n \"curtailedQuantity\": 6.5,\n \"curtailmentReason\": \"GRID_OUTAGE\",\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T12:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 8.5,\n \"allocatedEnergy\": 8.5,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T14:30:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_update", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_update" + ] + }, + "description": "On_update request: on-update-response-curtailment" + }, + "response": [] + } + ] + }, + { + "name": "publish", + "item": [ + { + "name": "publish-catalog", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"catalog_publish\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"catalogs\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Catalog\",\n \"beckn:id\": \"catalog-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Trading Catalog\"\n },\n \"beckn:bppId\": \"bpp.energy-provider.com\",\n \"beckn:bppUri\": \"https://bpp.energy-provider.com\",\n \"beckn:items\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 30.5 kWh\",\n \"beckn:shortDesc\": \"Carbon Offset Certified Solar Energy\",\n \"beckn:longDesc\": \"High-quality solar energy from verified source with carbon offset certification\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"certificationStatus\": \"Carbon Offset Certified\",\n \"meterId\": \"der://meter/100200300\",\n \"availableQuantity\": 30.5,\n \"productionWindow\": [\n {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T10:00:00Z\",\n \"schema:endTime\": \"2024-10-04T18:00:00Z\"\n }\n ],\n \"sourceVerification\": {\n \"verified\": true,\n \"verificationDate\": \"2024-09-01T00:00:00Z\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert.pdf\"\n ]\n },\n \"productionAsynchronous\": true\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 50.0 kWh\",\n \"beckn:shortDesc\": \"Standard Solar Energy\",\n \"beckn:longDesc\": \"Reliable solar energy from verified source\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyResource/v0.2/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"certificationStatus\": \"Standard Certified\",\n \"meterId\": \"der://meter/100200301\",\n \"availableQuantity\": 50.0,\n \"productionWindow\": [\n {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T08:00:00Z\",\n \"schema:endTime\": \"2024-10-04T16:00:00Z\"\n }\n ],\n \"sourceVerification\": {\n \"verified\": true,\n \"verificationDate\": \"2024-09-01T00:00:00Z\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert-2.pdf\"\n ]\n },\n \"productionAsynchronous\": true\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Daily Settlement Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"schema:unitText\": \"kWh\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"wheelingCharges\": {\n \"amount\": 2.5,\n \"currency\": \"USD\",\n \"description\": \"PG&E Grid Services wheeling charge\"\n },\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-04T23:59:59Z\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 30.5,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n }\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Bulk Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-002\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.12,\n \"schema:priceCurrency\": \"USD\",\n \"schema:unitText\": \"kWh\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"WEEKLY\",\n \"wheelingCharges\": {\n \"amount\": 2.0,\n \"currency\": \"USD\",\n \"description\": \"PG&E Grid Services wheeling charge\"\n },\n \"minimumQuantity\": 10.0,\n \"maximumQuantity\": 500.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-11T23:59:59Z\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 50.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n }\n }\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/publish", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "publish" + ] + }, + "description": "Publish request: publish-catalog" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-trading:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-trading-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-trading-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bpp_adapter_url", + "value": "http://localhost:8082/bpp/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-devkit/postman/p2p-trading:UtilityBPP-DEG.postman_collection.json b/testnet/p2p-trading-devkit/postman/p2p-trading:UtilityBPP-DEG.postman_collection.json new file mode 100644 index 00000000..3d48f072 --- /dev/null +++ b/testnet/p2p-trading-devkit/postman/p2p-trading:UtilityBPP-DEG.postman_collection.json @@ -0,0 +1,131 @@ +{ + "info": { + "_postman_id": "7ddb28db-3d54-4c39-8e85-5ef57543370e", + "name": "p2p-trading:UtilityBPP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Utility BPP (Transmission/Grid Provider Platform) implementing p2p-trading APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "confirm", + "item": [ + { + "name": "cascaded-confirm-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": 15.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: cascaded-confirm-request" + }, + "response": [] + } + ] + }, + { + "name": "init", + "item": [ + { + "name": "cascaded-init-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"beckn:id\": \"buyer-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOrder/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": 15.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyOrderItem/v0.1/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyCustomer/v0.1/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"UTIL-CUST-123456\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"beckn:id\": \"offer-morning-001\",\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/tpddl-p2p-trading-pilot-v20260201/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"sourceMeterId\": \"der://meter/100200300\",\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n },\n \"beckn:price\": {\n \"value\": 0.15,\n \"currency\": \"USD\",\n \"unitText\": \"kWh\"\n },\n \"beckn:maxQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\",\n \"unitCode\": \"KWH\"\n },\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: cascaded-init-request" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-trading:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-trading-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-trading-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bpp_adapter_url", + "value": "http://localhost:8082/bpp/caller" + }, + { + "key": "bap_adapter_url", + "value": "http://localhost:8081/bap/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/.DS_Store b/testnet/p2p-trading-interdiscom-devkit/.DS_Store new file mode 100644 index 00000000..9a04531d Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/.DS_Store differ diff --git a/testnet/p2p-trading-interdiscom-devkit/.grok/settings.json b/testnet/p2p-trading-interdiscom-devkit/.grok/settings.json new file mode 100644 index 00000000..a2d9deb4 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/.grok/settings.json @@ -0,0 +1,3 @@ +{ + "model": "grok-code-fast-1" +} \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/README.md b/testnet/p2p-trading-interdiscom-devkit/README.md new file mode 100644 index 00000000..08ac1b48 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/README.md @@ -0,0 +1,159 @@ +# P2P Energy Trading Devkit + +Goal of this devkit is to enable a developer to test round trip Beckn v2.0 mock messages between all network actors (BAP, Prosumer BPP (called BPP for brevity), Utility BPP, see [implementation-guide](/docs/implementation-guides/v2/P2P_Trading/P2P_Trading_implementation_guide_DRAFT.md)), on their local machine within a few minutes. + +It is a *batteries included* sandbox environment that requires minimal setup, and has environment variables pre-configured, connections to Catalog Discovery Service and Dedi test registry service pre-configured. + +## Setup + +1. Install [docker desktop](https://www.docker.com/products/docker-desktop) & run it in background. +2. Install [git](https://git-scm.com/downloads) ensure that git is added to your system path. +3. Install [postman](https://www.postman.com/downloads/) +4. Clone this repository using git command line interface and navigate to the install directory. (TODO: branch p2p-trading needs to be removed after merge to main from the following command) + +``` +git clone -b p2p-trading https://github.com/beckn/DEG.git +cd DEG/testnet/p2p-trading-interdiscom-devkit/install +``` + +### References used in this guide +- Beckn 2.0 sandbox [repo](https://github.com/beckn/sandbox), [image](https://hub.docker.com/r/fidedocker/sandbox-2.0). +- Beckn-Onix [repo](https://github.com/Beckn-One/beckn-onix), [image](https://hub.docker.com/r/fidedocker/onix-adapter). +- DeDi (decentralized directory, a Beckn-One service based open DeDi [protocol](https://github.com/finternet-io/dedi)) website [production](https://dedi.global/), [test](https://publish-test.dedi.global/). We use test DeDi server for this demo. +- Registry service (cache layer on top of DeDi, a Beckn-One service) [production](https://api.beckn.io/registry), [test](http://api.dev.beckn.io/registry). We use test registry server for this demo. + + +## Test network + +1. Spin up the containers using docker compose. Verify that the following containers are running: redis, onix-bap, onix-bpp, onix-utilitybpp, sandbox-bap, sandbox-bpp, sandbox-utilitybpp. You can also navigate to docker desktop and check the containers and their logs. + ``` + docker compose -f ./docker-compose-adapter-p2p.yml up -d --build + docker ps + ``` + +2. Open postman and import the folder `DEG/testnet/p2p-energy-trading-devkit/postman` to import all the collections and environment variables. + +3. Start by publishing a mock catalog to the catalog discovery service using the collection `P2P-Trading:CDSupload-DEG`. + +4. Check if you can see this catalog via a BAP by using the collection `P2P-Trading:BAP-DEG/discover`. Note that this can be flaky and may timeout sometimes due to CDS unavailability. In that case try again. + +5. Use the collection `P2P-Trading:BAP-DEG` (select, init, confirm, status queries) to test the round trip Beckn v2.0 mock messages between BAP and BPP. The query reponse will show an "Ack" message, and detailed `on_select`, `on_init`, `on_confirm`, `on_status` messages from BPP should be visible in the BAP logs. + +6. Use the collection `P2P-Trading:BPP-DEG` (on_select, on_init, on_confirm, on_status) to test only the BPP to BAP trip Beckn v2.0 mock messages between BPP to BAP. + +7. Use the collection `P2P-Trading:BPP-DEG` (cascaded_init) to test only the BPP to Utility BPP round trip Beckn v2.0 mock messages. The query reponse will show an "Ack" message, and detailed `on_init`, `on_confirm`, `on_status` messages from Utility BPP should be visible in the Prosumer BPP logs. + +8. Use the collection `P2P-Trading:UtilityBPP-DEG` (cascaded_init) to test only the Utility BPP to prosumer BPP Beckn v2.0 mock messages. The query reponse will show an "Ack" message, and detailed `on_init`, `on_confirm`, `on_status` messages from Utility BPP should be visible in the Prosumer BPP logs. + +9. Stop the containers using docker compose + ``` + docker compose -f ./docker-compose-adapter-p2p.yml down + ``` + +## Under the hood + +1. BAP `discover` calls are routed to Catalog Discovery Service url `https://34.93.141.21.sslip.io/beckn` defined [here](./config/local-p2p-routing-BuyerBAPCaller.yaml) +2. Public keys from network participants are fetched from Beckn One registry service `http://api.dev.beckn.io/registry/dedi` which acts as a cache layer on top of Dedi registry, and are used to confirm that Beckn messages are sent by the trusted actor (and not by an imposter). The namespace and registry entries in Dedi are preconfigured in yaml files within config folder. The process of creating a DiDi namespace and registries is defined [here](https://beckn-labs.gitbook.io/beckn-labs-docs/beckn-registry/publishing-subscriber-details) and also further down on this page. For testing, it is recommended to create records in Dedi registry which are then cached by Beckn One registry service every hour. The registry records such as `p2p-trading-sandbox1.com` (BAP), `p2p-trading-sandbox2.com` (BPP), `p2p-trading-sandbox3.com` (utility BPP) were added beforehand, and used in this devkit. An example API call during runtime to registry service looks like [this](https://api.dev.beckn.io/registry/dedi/lookup/p2p-trading-sandbox1.com/subscribers.beckn.one/76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ). +3. Routing rules within each actor are defined in config for [BAP](./config/local-p2p-bap.yaml), [BPP](./config/local-p2p-bpp.yaml), [Utility BPP](./config/local-p2p-utilitybpp.yaml). +4. Network between various actors is defined in docker-compose-adapter-p2p.yml +5. Variables are preconfigured to following values. + | Variable Name | Value | Notes | + | :-------------------------- | :----------------------------------------- | :-------------------------- | + | `domain` | `beckn.one:deg:p2p-trading-interdiscom:2.0.0` | | + | `version` | `2.0.0` | | + | `bap_id` | `p2p-trading-sandbox1.com` | | + | `bap_uri` | `http://onix-bap:8081/bap/receiver` | | + | `bpp_id` | `p2p-trading-sandbox2.com` | | + | `bpp_uri` | `http://onix-bpp:8082/bpp/receiver` | | + | `bpp_bapreceiver_uri` | `http://onix-bpp:8082/bap/receiver` | | + | `utilitybpp_id` | `p2p-trading-sandbox3.com` | | + | `utilitybpp_uri` | `http://onix-utilitybpp:8083/bpp/receiver` | | + | `bap_adapter_url` | `http://localhost:8081/bap/caller` | BAP collection only | + | `bpp_adapter_url` | `http://localhost:8082/bpp/caller` | BPP collection only | + | `bpp_adapter_bapcaller_url` | `http://localhost:8082/bap/caller` | BPP collection only | + | `utilitybpp_adapter_url` | `http://localhost:8083/bpp/caller` | Utility BPP collection only | + | `transaction_id` | `3769776b-88b4-469d-9ee2-95044fe5dafc` | | + | `iso_date` | `2025-01-01T10:00:00Z` | | + | `cds_url` | `https://34.93.141.21.sslip.io` | CDS Upload collection only | + +## Routing + +
+P2P Routing Diagram + +![P2P Routing Diagram](./assets/p2p-routing-diagram.png) + +
+ +## Next steps towards a production network: + +TBD + +## Troubleshooting + +- If one of your onix containers fails to start due to `failed to load SchemaValidator plugin` error, + you may have an older stale image of `fidedocker/onix-adapter` [here](https://hub.docker.com/r/fidedocker/onix-adapter). + +## Setting up Dedi registry + +A more complete documentation is located [here](https://beckn-labs.gitbook.io/beckn-labs-docs/beckn-registry/publishing-subscriber-details), which also includes a [video walk-through](https://www.loom.com/share/e0293309701348dc95719a98b957d12c?sid=04b8dc00-51de-46ac-82ce-adc1a0060409). Here are just the steps taken to create a dummy registry for this testnet. + + +- Registered in the DeDi [dev website](https://publish-test.dedi.global/) and created two + unverified (verification happens when you own a fully qualified domain name, and can store a publicly viewable dedi verification file on it) namespaces. Namespaces should be one per atomic entity like an organization. Here it was created for utility and a network participant + which is both a BAP & BPP. Ideally each network participant should claim their own namespace, add registries to it, create registry records within each registry (say for their BAP and BPP). + +
+ Test dedi namespaces + + ![Test dedi namespaces](./assets/dedi-dashboard.png) + +
+- Registries created within namespace `np_subscriber_detail` are as follows. + +
+ Test network participant registries + + ![Test network participant registries](./assets/dedi-np-registry-records.png) + +
+- A specific registry record created for a participant BAP looks like below. + Note that it asks for a various fields such as `url` which is the callback url of subscriber, `type` (BAP or BPP or BG or CDS), `countries`, `subscriber_id`, `domain = 'beckn.one:deg:p2p-trading'` (globally unique FQDN of platform) and `signing_public_key`. Public and private key pairs can be generated by the utility script located [here](https://github.com/Beckn-One/beckn-onix/blob/main/install/generate-ed25519-keys.go). e.g. `go run generate-ed25519-keys.go ` + +
+ BAP sandbox 1 registry record + + ![BAP sandbox 1 registry record](./assets/dedi-np-registry-record-bap.png) + +
+- Similar registry records are created for BPP + +
+ BPP sandbox 2 registry record + + ![BPP sandbox 2 registry record](./assets/dedi-np-registry-record-bpp.png) + +
+- And another one for utility BPP. + +
+ Utility BPP sandbox 3 registry record + + ![Utility BPP sandbox 3 registry record](./assets/dedi-utility-registry-record-utilitybpp.png) + +
+- Within the beckn-onix configuration (`config/*.yaml` files) use the `networkParticipant` (`subscriber_id` from DeDi setup), `keyId` (Record ID from DeDi setup) along with the signing & encryption private and public keys. +- Finally enable caching of the DeDi registry by registry service by completeing last step from [these instructions](https://beckn-labs.gitbook.io/beckn-labs-docs/beckn-registry/publishing-subscriber-details). + +## Regenerating Postman Collection + +To regenerate the Postman collections for this devkit: + +```bash +# From DEG repository root +python3 scripts/generate_postman_collection.py --devkit p2p-trading-interdiscom --role BAP --output-dir testnet/p2p-trading-interdiscom-devkit/postman +python3 scripts/generate_postman_collection.py --devkit p2p-trading-interdiscom --role BPP --output-dir testnet/p2p-trading-interdiscom-devkit/postman +python3 scripts/generate_postman_collection.py --devkit p2p-trading-interdiscom --role UtilityBPP --output-dir testnet/p2p-trading-interdiscom-devkit/postman +``` + +This devkit uses the `EnergyTradeOrderInterUtility` schema which extends `EnergyTradeOrder` with utility/discom identifiers (`utilityIdBuyer`, `utilityIdSeller`) for inter-discom P2P trading scenarios. diff --git a/testnet/p2p-trading-interdiscom-devkit/assets/dedi-dashboard.png b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-dashboard.png new file mode 100644 index 00000000..f3170f8e Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-dashboard.png differ diff --git a/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-record-bap.png b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-record-bap.png new file mode 100644 index 00000000..31069edd Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-record-bap.png differ diff --git a/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-record-bpp.png b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-record-bpp.png new file mode 100644 index 00000000..dd9edf46 Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-record-bpp.png differ diff --git a/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-records.png b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-records.png new file mode 100644 index 00000000..ae2cc58e Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-np-registry-records.png differ diff --git a/testnet/p2p-trading-interdiscom-devkit/assets/dedi-utility-registry-record-utilitybpp.png b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-utility-registry-record-utilitybpp.png new file mode 100644 index 00000000..852c4469 Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-utility-registry-record-utilitybpp.png differ diff --git a/testnet/p2p-trading-interdiscom-devkit/assets/dedi-utility-registry-records.png b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-utility-registry-records.png new file mode 100644 index 00000000..a28cf93e Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/assets/dedi-utility-registry-records.png differ diff --git a/testnet/p2p-trading-interdiscom-devkit/assets/p2p-routing-diagram.png b/testnet/p2p-trading-interdiscom-devkit/assets/p2p-routing-diagram.png new file mode 100644 index 00000000..b8979902 Binary files /dev/null and b/testnet/p2p-trading-interdiscom-devkit/assets/p2p-routing-diagram.png differ diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-bap.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-bap.yaml new file mode 100644 index 00000000..bd2031ab --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-bap.yaml @@ -0,0 +1,149 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8081 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: bapTxnReceiver + path: /bap/receiver/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox1.com + keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ + signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + signingPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + encrPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + encrPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-BuyerBAPReceiver.yaml + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - id: degledgerrecorder + config: + ledgerHost: "https://34.93.166.38.sslip.io" + role: "BUYER" + actions: "on_confirm,on_status" # Handle both actions + enabled: "true" + asyncTimeout: "30000" + # Signing config (same keys as simplekeymanager) + signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + networkParticipant: p2p-trading-sandbox1.com + keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ + steps: + - validateSign + - addRoute + - validateSchema + - degledgerrecorder + + - name: bapTxnCaller + path: /bap/caller/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox1.com + keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ + signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + signingPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + encrPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= + encrPublicKey: KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-BuyerBAPCaller.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - addRoute + - sign + - validateSchema \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-bpp.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-bpp.yaml new file mode 100644 index 00000000..755b25e4 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-bpp.yaml @@ -0,0 +1,265 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8082 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: bppTxnReceiver + path: /bpp/receiver/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml + steps: + - validateSign + - addRoute + - validateSchema + + - name: bppTxnCaller + path: /bpp/caller/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bpp + steps: + - id: degledgerrecorder + config: + ledgerHost: "https://34.93.166.38.sslip.io" + role: "SELLER" + actions: "on_confirm,on_status" # Handle both actions + enabled: "true" + asyncTimeout: "30000" + # Signing config (same keys as simplekeymanager) + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + steps: + - addRoute + - sign + - validateSchema + - degledgerrecorder + + # BAP Modules: For cascaded calls to utility BPP + # This module receives responses FROM utility BPP (on_init, on_confirm, on_update) + - name: bapTxnReceiver + path: /bap/receiver/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - validateSign + - addRoute + - validateSchema + + # This module sends cascaded requests TO utility BPP (init, confirm) + - name: bapTxnCaller + path: /bap/caller/ + handler: + type: std + role: bap + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox2.com + keyId: 76EU7Mvhh7jaEf7Lcac5R1PPeFL4ddr1ALs2QYzpyTRE8g15Yr1p7C + signingPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + signingPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + encrPrivateKey: AC72WfPu5ly3T7rXfRHrLA/l++BxbsNwe0qitgT9u6U= + encrPublicKey: E9w4QejjJ6d+VODJlDKJcpI93RY3Bg4RQp4Rs1F9oQ8= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bap + steps: + - addRoute + - sign + - validateSchema \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-BuyerBAPCaller.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-BuyerBAPCaller.yaml new file mode 100644 index 00000000..80c82ff6 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-BuyerBAPCaller.yaml @@ -0,0 +1,20 @@ +routingRules: + - version: "2.0.0" + targetType: "bpp" + endpoints: + - select + - init + - confirm + - status + - track + - cancel + - update + - rating + - support + + - version: "2.0.0" + targetType: "url" + target: + url: "https://34.93.141.21.sslip.io/beckn" #test CDS URL + endpoints: + - discover diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-BuyerBAPReceiver.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-BuyerBAPReceiver.yaml new file mode 100644 index 00000000..7dfa0336 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-BuyerBAPReceiver.yaml @@ -0,0 +1,13 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bap:3001/api/bap-webhook" + endpoints: + - on_discover + - on_select + - on_init + - on_confirm + - on_status + - on_update + - on_cancel diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml new file mode 100644 index 00000000..dad97c19 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBAPCaller-to-UtilityBPP.yaml @@ -0,0 +1,7 @@ +routingRules: + - version: "2.0.0" + targetType: "bpp" + endpoints: + - init + - confirm + diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml new file mode 100644 index 00000000..41e177b2 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBAPReceiver-from-UtilityBPP.yaml @@ -0,0 +1,10 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bpp:3002/api/bap-webhook" + endpoints: + - on_init + - on_confirm + - on_update + diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml new file mode 100644 index 00000000..8576bdf1 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBPPCaller-to-BuyerBAP.yaml @@ -0,0 +1,20 @@ +routingRules: + - version: "2.0.0" + targetType: "bap" + endpoints: + - on_status + - on_cancel + - on_update + - on_select + - on_init + - on_confirm + - on_track + - on_rating + - on_support + + - version: "2.0.0" + targetType: "url" + target: + url: "https://34.93.141.21.sslip.io/beckn/catalog" + endpoints: + - publish diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml new file mode 100644 index 00000000..9a0897c9 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-SellerBPPReceiver-from-BuyerBAP.yaml @@ -0,0 +1,22 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bpp:3002/api/webhook" + endpoints: + - select + - init + - confirm + - status + - track + - cancel + - update + - rating + - support + + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-bpp:3002/api/webhook" + endpoints: + - catalog/on_publish #publish response from CDS after catalog update \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-UtilityBPPCaller.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-UtilityBPPCaller.yaml new file mode 100644 index 00000000..adc49d57 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-UtilityBPPCaller.yaml @@ -0,0 +1,9 @@ +routingRules: + - version: "2.0.0" + targetType: "bap" + endpoints: + - on_init # response to cascaded init from P2P Trading BPP + - on_confirm # response to cascaded confirm from P2P Trading BPP + - on_update # update sent to P2P Trading BPP after fulfillment + + diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-UtilityBPPReceiver.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-UtilityBPPReceiver.yaml new file mode 100644 index 00000000..2cae7f43 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-routing-UtilityBPPReceiver.yaml @@ -0,0 +1,10 @@ +routingRules: + - version: "2.0.0" + targetType: "url" + target: + url: "http://sandbox-utilitybpp:3003/api/webhook" + endpoints: + - init # cascaded init from P2P Trading BPP + - confirm # cascaded confirm from P2P Trading BPP + + diff --git a/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-utilitybpp.yaml b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-utilitybpp.yaml new file mode 100644 index 00000000..edeafe1f --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/config/local-p2p-utilitybpp.yaml @@ -0,0 +1,131 @@ +appName: "onix-local" +log: + level: debug + destinations: + - type: stdout + contextKeys: + - transaction_id + - message_id + - subscriber_id + - module_id +http: + port: 8083 + timeout: + read: 30 + write: 30 + idle: 30 +pluginManager: + root: ./plugins +modules: + - name: utilitybppTxnReceiver + path: /bpp/receiver/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox3.com + keyId: 76EU8cNkz3dBEVaR5THuyCciMv9FbA2QqDADHX88WPyYP4v5Cp9ADD + signingPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + signingPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + encrPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + encrPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + signValidator: + id: signvalidator + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-UtilityBPPReceiver.yaml + steps: + - validateSign + - addRoute + - validateSchema + + - name: utilitybppTxnCaller + path: /bpp/caller/ + handler: + type: std + role: bpp + httpClientConfig: + maxIdleConns: 1000 + maxIdleConnsPerHost: 200 + idleConnTimeout: 300s + responseHeaderTimeout: 5s + plugins: + registry: + id: dediregistry + config: + url: https://api.dev.beckn.io/registry/dedi + registryName: subscribers.beckn.one + timeout: 10 + keyManager: + id: simplekeymanager + config: + networkParticipant: p2p-trading-sandbox3.com + keyId: 76EU8cNkz3dBEVaR5THuyCciMv9FbA2QqDADHX88WPyYP4v5Cp9ADD + signingPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + signingPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + encrPrivateKey: YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc= + encrPublicKey: vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog= + schemaValidator: + id: schemav2validator + config: + type: url + location: https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/api/beckn.yaml + cacheTTL: "3600" + extendedSchema_enabled: "true" + extendedSchema_cacheTTL: "86400" + extendedSchema_maxCacheSize: "100" + extendedSchema_downloadTimeout: "30" + extendedSchema_allowedDomains: "raw.githubusercontent.com,schemas.beckn.org" + # P2P Energy Trading Profile: https://github.com/beckn/protocol-specifications-v2/tree/main/profiles/p2p-energy-trading/v0.3 + x-profile: "p2p-energy-trading/v0.3" + cache: + id: cache + config: + addr: redis:6379 + router: + id: router + config: + routingConfig: ./config/local-p2p-routing-UtilityBPPCaller.yaml + signer: + id: signer + middleware: + - id: reqpreprocessor + config: + uuidKeys: transaction_id,message_id + role: bpp + steps: + - addRoute + - sign + - validateSchema diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/README.md b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/README.md new file mode 100644 index 00000000..3dd35716 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/README.md @@ -0,0 +1,90 @@ +# DISCOM Signing Kit + +SDKs for utility companies (DISCOMs) to sign Beckn protocol payloads for the DEG Ledger Service. + +## What it does + +**In:** JSON payload (any beckn action — `confirm`, `on_confirm`, `on_status`, etc.) +**Out:** `Authorization` header value with Ed25519 signature + +``` +Payload bytes ──► PayloadSigner.SignPayload() ──► Authorization header string +``` + +The Authorization header follows the [Beckn Protocol signing specification](https://github.com/beckn/beckn-onix): + +``` +Signature keyId="{subscriberId}|{keyId}|ed25519",algorithm="ed25519",created="{unix_ts}",expires="{unix_ts}",headers="(created) (expires) digest",signature="{base64_sig}" +``` + +## Signing algorithm + +1. **BLAKE2-512** hash of the raw JSON payload body +2. Build signing string: `(created): {ts}\n(expires): {ts}\ndigest: BLAKE-512={base64_hash}` +3. **Ed25519** sign the signing string using the 32-byte private key seed +4. Format the `Authorization` header with `keyId`, timestamps, and base64 signature + +## Configuration + +You need three values from your beckn-onix YAML config (`simplekeymanager` or `degledgerrecorder` section): + +| Field | Example | Description | +|-------|---------|-------------| +| `subscriberId` / `networkParticipant` | `p2p-trading-sandbox1.com` | Your registered network participant ID | +| `keyId` | `76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ` | Unique key ID registered in the Beckn DeDi registry | +| `signingPrivateKey` | `Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=` | Base64-encoded Ed25519 seed (32 bytes) | + +These map directly to your `local-p2p-bap.yaml` config: + +```yaml +# From degledgerrecorder config +signingPrivateKey: Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw= +networkParticipant: p2p-trading-sandbox1.com +keyId: 76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ +``` + +## SDKs + +### [Go](./golang/) + +```go +s, _ := signer.New(signer.Config{ + SubscriberID: "p2p-trading-sandbox1.com", + UniqueKeyID: "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ", + SigningPrivateKey: "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=", +}) + +authHeader, _ := s.SignPayload(payloadBytes) +req.Header.Set("Authorization", authHeader) +``` + +**Run tests:** `cd golang && go test -v ./...` + +### [ASP.NET / C#](./aspdotnet/) + +```csharp +var signer = new PayloadSigner(new SignerConfig { + SubscriberId = "p2p-trading-sandbox1.com", + UniqueKeyId = "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ", + SigningPrivateKey = "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=", +}); + +string authHeader = signer.SignPayload(payloadJson); +request.Headers.Add("Authorization", authHeader); +``` + +**Run tests:** `cd aspdotnet && dotnet test` + +## Verification (optional) + +Both SDKs also include a verifier to validate incoming signed requests: + +```go +// Go +err := signer.Verify(body, authHeader, senderPublicKey) +``` + +```csharp +// C# +PayloadVerifier.Verify(body, authHeader, senderPublicKey); +``` diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/BecknSigner.Tests.csproj b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/BecknSigner.Tests.csproj new file mode 100644 index 00000000..f7eff054 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/BecknSigner.Tests.csproj @@ -0,0 +1,21 @@ + + + + net10.0 + enable + enable + false + true + + + + + + + + + + + + + diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/PayloadSignerTests.cs b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/PayloadSignerTests.cs new file mode 100644 index 00000000..9a42bf0d --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/PayloadSignerTests.cs @@ -0,0 +1,168 @@ +using System.Text; +using BecknSigner; +using Xunit; + +namespace BecknSigner.Tests; + +/// +/// Tests using the same keys as local-p2p-bap.yaml (sandbox1). +/// +public class PayloadSignerTests +{ + private const string TestSubscriberId = "p2p-trading-sandbox1.com"; + private const string TestKeyId = "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ"; + private const string TestPrivateKey = "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw="; + private const string TestPublicKey = "KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE="; + + private static readonly string SamplePayload = @"{ + ""context"": { + ""version"": ""2.0.0"", + ""action"": ""confirm"", + ""timestamp"": ""2024-10-04T10:25:00Z"", + ""message_id"": ""msg-confirm-001"", + ""transaction_id"": ""txn-energy-001"", + ""bap_id"": ""bap.energy-consumer.com"", + ""bap_uri"": ""https://bap.energy-consumer.com"", + ""bpp_id"": ""bpp.energy-provider.com"", + ""bpp_uri"": ""https://bpp.energy-provider.com"", + ""domain"": ""beckn.one:deg:p2p-trading:2.0.0"" + }, + ""message"": { + ""order"": { + ""@type"": ""beckn:Order"", + ""beckn:orderStatus"": ""CREATED"", + ""beckn:seller"": ""provider-solar-farm-001"" + } + } +}"; + + private PayloadSigner CreateSigner() => new(new SignerConfig + { + SubscriberId = TestSubscriberId, + UniqueKeyId = TestKeyId, + SigningPrivateKey = TestPrivateKey, + }); + + [Fact] + public void SignAndVerify_RoundTrip_Succeeds() + { + var signer = CreateSigner(); + var body = Encoding.UTF8.GetBytes(SamplePayload); + + string authHeader = signer.SignPayload(body); + + // Structure checks + Assert.StartsWith("Signature ", authHeader); + Assert.Contains($"{TestSubscriberId}|{TestKeyId}|ed25519", authHeader); + Assert.Contains("algorithm=\"ed25519\"", authHeader); + + // Verify succeeds + PayloadVerifier.Verify(body, authHeader, TestPublicKey); + } + + [Fact] + public void SignPayload_StringOverload_ProducesSameResult() + { + var signer = CreateSigner(); + + // String and byte[] should produce valid signatures + string authFromString = signer.SignPayload(SamplePayload); + Assert.StartsWith("Signature ", authFromString); + + var body = Encoding.UTF8.GetBytes(SamplePayload); + PayloadVerifier.Verify(body, authFromString, TestPublicKey); + } + + [Fact] + public void SignPayloadDetailed_Returns300SecondWindow() + { + var signer = CreateSigner(); + var body = Encoding.UTF8.GetBytes(SamplePayload); + + var result = signer.SignPayloadDetailed(body); + + Assert.Equal(300, result.ExpiresAt - result.CreatedAt); + Assert.NotEmpty(result.Signature); + Assert.NotEmpty(result.AuthorizationHeader); + } + + [Fact] + public void Verify_RejectsTamperedPayload() + { + var signer = CreateSigner(); + var body = Encoding.UTF8.GetBytes(SamplePayload); + + string authHeader = signer.SignPayload(body); + + // Tamper + var tampered = Encoding.UTF8.GetBytes(SamplePayload.Replace("confirm", "cancel")); + + Assert.Throws( + () => PayloadVerifier.Verify(tampered, authHeader, TestPublicKey)); + } + + [Fact] + public void Verify_RejectsExpiredSignature() + { + var signer = new PayloadSigner(new SignerConfig + { + SubscriberId = TestSubscriberId, + UniqueKeyId = TestKeyId, + SigningPrivateKey = TestPrivateKey, + ExpiryDuration = TimeSpan.FromSeconds(1), + }); + var body = Encoding.UTF8.GetBytes(SamplePayload); + + // Sign in the past + var past = DateTimeOffset.UtcNow.AddMinutes(-10); + var result = signer.SignPayloadAt(body, past); + + var ex = Assert.Throws( + () => PayloadVerifier.Verify(body, result.AuthorizationHeader, TestPublicKey)); + Assert.Contains("expired", ex.Message, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void Verify_RejectsWrongPublicKey() + { + var signer = CreateSigner(); + var body = Encoding.UTF8.GetBytes(SamplePayload); + + string authHeader = signer.SignPayload(body); + + // Use sandbox3 public key instead of sandbox1 + string wrongPublicKey = "vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog="; + + Assert.Throws( + () => PayloadVerifier.Verify(body, authHeader, wrongPublicKey)); + } + + [Fact] + public void Constructor_ValidatesConfig() + { + Assert.Throws(() => new PayloadSigner(new SignerConfig + { + SubscriberId = "", + UniqueKeyId = TestKeyId, + SigningPrivateKey = TestPrivateKey, + })); + + Assert.Throws(() => new PayloadSigner(new SignerConfig + { + SubscriberId = TestSubscriberId, + UniqueKeyId = TestKeyId, + SigningPrivateKey = Convert.ToBase64String(new byte[] { 1, 2, 3 }), // wrong size + })); + } + + [Fact] + public void ParseKeyId_WorksCorrectly() + { + var (sub, key, alg) = PayloadVerifier.ParseKeyId("p2p-trading-sandbox1.com|76EU8aUq|ed25519"); + Assert.Equal("p2p-trading-sandbox1.com", sub); + Assert.Equal("76EU8aUq", key); + Assert.Equal("ed25519", alg); + + Assert.Throws(() => PayloadVerifier.ParseKeyId("bad-format")); + } +} diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/UsageExampleTests.cs b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/UsageExampleTests.cs new file mode 100644 index 00000000..91ccc892 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.Tests/UsageExampleTests.cs @@ -0,0 +1,82 @@ +using System.Text; +using BecknSigner; +using Xunit; + +namespace BecknSigner.Tests; + +/// +/// These tests demonstrate real-world usage patterns for utility companies. +/// Each test reads like a recipe: configure, sign, attach to HTTP request. +/// +public class UsageExampleTests +{ + /// + /// The simplest use case: sign a beckn payload and get the Authorization header. + /// This is the "in goes payload, out comes header" pattern. + /// + [Fact] + public void Example_SignPayloadForLedgerService() + { + // -- Config from your YAML (degledgerrecorder section) -- + var signer = new PayloadSigner(new SignerConfig + { + SubscriberId = "p2p-trading-sandbox1.com", + UniqueKeyId = "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ", + SigningPrivateKey = "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=", + }); + + // -- Your beckn payload (confirm, on_confirm, on_status, etc.) -- + string payload = @"{ + ""context"": { + ""action"": ""on_confirm"", + ""domain"": ""beckn.one:deg:p2p-trading:2.0.0"", + ""bap_id"": ""bap.energy-consumer.com"" + }, + ""message"": { + ""order"": { ""@type"": ""beckn:Order"", ""beckn:orderStatus"": ""ACTIVE"" } + } + }"; + + // -- Sign it -- + string authHeader = signer.SignPayload(payload); + + // -- Attach to your HTTP request -- + // using var client = new HttpClient(); + // var request = new HttpRequestMessage(HttpMethod.Post, "https://ledger.example.com/record"); + // request.Content = new StringContent(payload, Encoding.UTF8, "application/json"); + // request.Headers.Add("Authorization", authHeader); + // var response = await client.SendAsync(request); + + // Verify the header is well-formed + Assert.StartsWith("Signature keyId=\"p2p-trading-sandbox1.com|76EU8aUq", authHeader); + Assert.Contains("algorithm=\"ed25519\"", authHeader); + Assert.Contains("headers=\"(created) (expires) digest\"", authHeader); + } + + /// + /// Verify an incoming signed request from another participant. + /// + [Fact] + public void Example_VerifyIncomingRequest() + { + // Simulate: the sender signs with their private key + var senderSigner = new PayloadSigner(new SignerConfig + { + SubscriberId = "p2p-trading-sandbox3.com", + UniqueKeyId = "76EU8cNkz3dBEVaR5THuyCciMv9FbA2QqDADHX88WPyYP4v5Cp9ADD", + SigningPrivateKey = "YW0ObrW6Ca+RLi+rVoxavW6dsC3BuzAx2v9qfutFUcc=", + }); + + string payload = @"{""context"":{""action"":""confirm""},""message"":{}}"; + byte[] body = Encoding.UTF8.GetBytes(payload); + string authHeader = senderSigner.SignPayload(body); + + // Receiver side: verify using sender's PUBLIC key + // (In production, you'd look this up from the Beckn DeDi registry) + string senderPublicKey = "vSAbdarosQEp7CGf18oYIjdG9ewS1gESsmY3TmfzZog="; + PayloadVerifier.Verify(body, authHeader, senderPublicKey); + + // If we get here, the signature is valid. + // A tampered payload would throw SignatureVerificationException. + } +} diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.sln b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.sln new file mode 100644 index 00000000..b3f3fb6e --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BecknSigner", "BecknSigner\BecknSigner.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BecknSigner.Tests", "BecknSigner.Tests\BecknSigner.Tests.csproj", "{B2C3D4E5-F678-90AB-CDEF-123456789012}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789012}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789012}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2C3D4E5-F678-90AB-CDEF-123456789012}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/BecknSigner.csproj b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/BecknSigner.csproj new file mode 100644 index 00000000..2d10ac6b --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/BecknSigner.csproj @@ -0,0 +1,18 @@ + + + + net10.0 + enable + enable + BecknSigner + + + + + + + + + + + diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/PayloadSigner.cs b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/PayloadSigner.cs new file mode 100644 index 00000000..5f3c5126 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/PayloadSigner.cs @@ -0,0 +1,157 @@ +using System.Text; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; +using Org.BouncyCastle.Crypto.Digests; + +namespace BecknSigner; + +/// +/// Configuration for the Beckn payload signer. +/// Values come from the simplekeymanager / degledgerrecorder config in your YAML. +/// +public record SignerConfig +{ + /// Network participant identifier (e.g. "p2p-trading-sandbox1.com"). + public required string SubscriberId { get; init; } + + /// Unique key identifier registered with the Beckn registry. + public required string UniqueKeyId { get; init; } + + /// Base64-encoded Ed25519 seed (32 bytes). + public required string SigningPrivateKey { get; init; } + + /// How long the signature is valid. Defaults to 5 minutes. + public TimeSpan ExpiryDuration { get; init; } = TimeSpan.FromMinutes(5); +} + +/// +/// Result of signing a payload. +/// +public record SignedResult +{ + /// Full value for the HTTP Authorization header. + public required string AuthorizationHeader { get; init; } + + /// Unix timestamp when the signature was created. + public required long CreatedAt { get; init; } + + /// Unix timestamp when the signature expires. + public required long ExpiresAt { get; init; } + + /// Raw base64-encoded Ed25519 signature. + public required string Signature { get; init; } +} + +/// +/// Signs Beckn protocol JSON payloads using Ed25519 + BLAKE2-512. +/// Produces an Authorization header compatible with the Beckn protocol specification. +/// +/// +/// var signer = new PayloadSigner(new SignerConfig +/// { +/// SubscriberId = "p2p-trading-sandbox1.com", +/// UniqueKeyId = "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ", +/// SigningPrivateKey = "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=" +/// }); +/// +/// string authHeader = signer.SignPayload(payloadBytes); +/// httpRequest.Headers.Add("Authorization", authHeader); +/// +public class PayloadSigner +{ + private readonly string _subscriberId; + private readonly string _uniqueKeyId; + private readonly Ed25519PrivateKeyParameters _privateKey; + private readonly TimeSpan _expiry; + + public PayloadSigner(SignerConfig config) + { + ArgumentException.ThrowIfNullOrEmpty(config.SubscriberId, nameof(config.SubscriberId)); + ArgumentException.ThrowIfNullOrEmpty(config.UniqueKeyId, nameof(config.UniqueKeyId)); + ArgumentException.ThrowIfNullOrEmpty(config.SigningPrivateKey, nameof(config.SigningPrivateKey)); + + var seed = Convert.FromBase64String(config.SigningPrivateKey); + if (seed.Length != 32) + throw new ArgumentException($"Private key seed must be 32 bytes, got {seed.Length}"); + + _privateKey = new Ed25519PrivateKeyParameters(seed, 0); + _subscriberId = config.SubscriberId; + _uniqueKeyId = config.UniqueKeyId; + _expiry = config.ExpiryDuration; + } + + /// + /// Signs a JSON payload and returns the Authorization header value. + /// + public string SignPayload(byte[] body) + { + return SignPayloadDetailed(body).AuthorizationHeader; + } + + /// + /// Signs a JSON payload string and returns the Authorization header value. + /// + public string SignPayload(string body) + { + return SignPayload(Encoding.UTF8.GetBytes(body)); + } + + /// + /// Signs a JSON payload and returns full signing details. + /// + public SignedResult SignPayloadDetailed(byte[] body) + { + return SignPayloadAt(body, DateTimeOffset.UtcNow); + } + + /// + /// Signs at a specific time (useful for deterministic testing). + /// + internal SignedResult SignPayloadAt(byte[] body, DateTimeOffset now) + { + long createdAt = now.ToUnixTimeSeconds(); + long expiresAt = now.Add(_expiry).ToUnixTimeSeconds(); + + string signingString = BuildSigningString(body, createdAt, expiresAt); + byte[] signingBytes = Encoding.UTF8.GetBytes(signingString); + + // Ed25519 sign + var edSigner = new Ed25519Signer(); + edSigner.Init(true, _privateKey); + edSigner.BlockUpdate(signingBytes, 0, signingBytes.Length); + byte[] signatureBytes = edSigner.GenerateSignature(); + + string signature = Convert.ToBase64String(signatureBytes); + + string header = $"Signature keyId=\"{_subscriberId}|{_uniqueKeyId}|ed25519\"," + + $"algorithm=\"ed25519\"," + + $"created=\"{createdAt}\"," + + $"expires=\"{expiresAt}\"," + + $"headers=\"(created) (expires) digest\"," + + $"signature=\"{signature}\""; + + return new SignedResult + { + AuthorizationHeader = header, + CreatedAt = createdAt, + ExpiresAt = expiresAt, + Signature = signature, + }; + } + + internal static string BuildSigningString(byte[] body, long createdAt, long expiresAt) + { + byte[] hash = Blake2bHash(body); + string digestB64 = Convert.ToBase64String(hash); + return $"(created): {createdAt}\n(expires): {expiresAt}\ndigest: BLAKE-512={digestB64}"; + } + + private static byte[] Blake2bHash(byte[] data) + { + var digest = new Blake2bDigest(512); + digest.BlockUpdate(data, 0, data.Length); + byte[] hash = new byte[64]; // 512 bits = 64 bytes + digest.DoFinal(hash, 0); + return hash; + } +} diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/PayloadVerifier.cs b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/PayloadVerifier.cs new file mode 100644 index 00000000..9a5f8f2b --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/aspdotnet/BecknSigner/PayloadVerifier.cs @@ -0,0 +1,98 @@ +using System.Text; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Signers; + +namespace BecknSigner; + +/// +/// Verifies Beckn protocol Authorization header signatures. +/// +public static class PayloadVerifier +{ + /// + /// Verifies that the Authorization header is a valid signature for the given body. + /// + /// The raw JSON payload bytes. + /// The full Authorization header value. + /// The sender's base64-encoded Ed25519 public key. + /// If verification fails. + public static void Verify(byte[] body, string authHeader, string publicKeyBase64) + { + VerifyAt(body, authHeader, publicKeyBase64, DateTimeOffset.UtcNow); + } + + /// + /// Verifies at a specific time (useful for testing). + /// + public static void VerifyAt(byte[] body, string authHeader, string publicKeyBase64, DateTimeOffset now) + { + var (created, expires, signature) = ParseAuthHeader(authHeader); + + long currentTime = now.ToUnixTimeSeconds(); + if (created > currentTime) + throw new SignatureVerificationException($"Signature not yet valid (created {created} > now {currentTime})"); + if (currentTime > expires) + throw new SignatureVerificationException($"Signature expired (expires {expires} < now {currentTime})"); + + byte[] signatureBytes = Convert.FromBase64String(signature); + string signingString = PayloadSigner.BuildSigningString(body, created, expires); + byte[] signingBytes = Encoding.UTF8.GetBytes(signingString); + + byte[] publicKeyBytes = Convert.FromBase64String(publicKeyBase64); + var publicKey = new Ed25519PublicKeyParameters(publicKeyBytes, 0); + + var verifier = new Ed25519Signer(); + verifier.Init(false, publicKey); + verifier.BlockUpdate(signingBytes, 0, signingBytes.Length); + + if (!verifier.VerifySignature(signatureBytes)) + throw new SignatureVerificationException("Signature verification failed"); + } + + /// + /// Parses the keyId field from an Authorization header. + /// Format: "subscriber_id|unique_key_id|algorithm" + /// + public static (string SubscriberId, string UniqueKeyId, string Algorithm) ParseKeyId(string keyId) + { + var parts = keyId.Split('|'); + if (parts.Length != 3) + throw new ArgumentException($"Invalid keyId format, expected 'subscriber|keyId|algorithm', got '{keyId}'"); + return (parts[0], parts[1], parts[2]); + } + + private static (long Created, long Expires, string Signature) ParseAuthHeader(string header) + { + header = header.StartsWith("Signature ", StringComparison.OrdinalIgnoreCase) + ? header["Signature ".Length..] + : header; + + var parameters = new Dictionary(); + foreach (var part in header.Split(',')) + { + var eqIndex = part.IndexOf('='); + if (eqIndex > 0) + { + string key = part[..eqIndex].Trim(); + string value = part[(eqIndex + 1)..].Trim().Trim('"'); + parameters[key] = value; + } + } + + if (!parameters.TryGetValue("created", out var createdStr) || !long.TryParse(createdStr, out long created)) + throw new SignatureVerificationException("Missing or invalid 'created' in auth header"); + + if (!parameters.TryGetValue("expires", out var expiresStr) || !long.TryParse(expiresStr, out long expires)) + throw new SignatureVerificationException("Missing or invalid 'expires' in auth header"); + + if (!parameters.TryGetValue("signature", out var signature)) + throw new SignatureVerificationException("Missing 'signature' in auth header"); + + return (created, expires, signature); + } +} + +public class SignatureVerificationException : Exception +{ + public SignatureVerificationException(string message) : base(message) { } +} diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/example_test.go b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/example_test.go new file mode 100644 index 00000000..055c1406 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/example_test.go @@ -0,0 +1,80 @@ +package signer_test + +import ( + "fmt" + "log" + "net/http" + "strings" + + signer "github.com/beckn/deg-discom-signing-kit" +) + +func Example_signAndSend() { + // 1. Configure the signer with your keys from the YAML config. + // These come from the simplekeymanager / degledgerrecorder config. + s, err := signer.New(signer.Config{ + SubscriberID: "p2p-trading-sandbox1.com", + UniqueKeyID: "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ", + SigningPrivateKey: "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=", + }) + if err != nil { + log.Fatal(err) + } + + // 2. Your beckn JSON payload (confirm, on_confirm, on_status, etc.) + payload := []byte(`{ + "context": { + "action": "confirm", + "domain": "beckn.one:deg:p2p-trading:2.0.0", + "bap_id": "bap.energy-consumer.com" + }, + "message": { + "order": { "@type": "beckn:Order", "beckn:orderStatus": "CREATED" } + } + }`) + + // 3. Sign it — this is the entire SDK surface. + authHeader, err := s.SignPayload(payload) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Authorization header generated:") + fmt.Println(authHeader[:50] + "...") + + // 4. Attach to HTTP request (e.g., posting to ledger service). + req, _ := http.NewRequest("POST", "https://ledger.example.com/record", strings.NewReader(string(payload))) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", authHeader) + + // req is now ready to send. + _ = req + + // Output: + // Authorization header generated: + // Signature keyId="p2p-trading-sandbox1.com|76EU8aUq... +} + +func Example_verify() { + // Verifier side: validate an incoming signed request. + payload := []byte(`{"context":{"action":"confirm"}}`) + + // First sign (simulating sender) + s, _ := signer.New(signer.Config{ + SubscriberID: "p2p-trading-sandbox1.com", + UniqueKeyID: "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ", + SigningPrivateKey: "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=", + }) + authHeader, _ := s.SignPayload(payload) + + // Verify (receiver side — you'd look up the public key from registry) + senderPublicKey := "KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE=" + err := signer.Verify(payload, authHeader, senderPublicKey) + if err != nil { + log.Fatal(err) + } + fmt.Println("Signature valid!") + + // Output: + // Signature valid! +} diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/go.mod b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/go.mod new file mode 100644 index 00000000..372db743 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/go.mod @@ -0,0 +1,7 @@ +module github.com/beckn/deg-discom-signing-kit + +go 1.21 + +require golang.org/x/crypto v0.31.0 + +require golang.org/x/sys v0.28.0 // indirect diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/go.sum b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/go.sum new file mode 100644 index 00000000..0b273f9b --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/go.sum @@ -0,0 +1,4 @@ +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/signer.go b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/signer.go new file mode 100644 index 00000000..429a0c14 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/signer.go @@ -0,0 +1,154 @@ +// Package signer provides Beckn protocol payload signing for DEG (Digital Energy Grid). +// +// It signs JSON payloads using Ed25519 + BLAKE2-512 and produces an Authorization +// header compatible with the Beckn protocol specification. +// +// Usage: +// +// s, err := signer.New(signer.Config{ +// SubscriberID: "p2p-trading-sandbox1.com", +// UniqueKeyID: "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ", +// SigningPrivateKey: "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=", +// }) +// +// authHeader, err := s.SignPayload(payloadBytes) +package signer + +import ( + "crypto/ed25519" + "encoding/base64" + "fmt" + "time" + + "golang.org/x/crypto/blake2b" +) + +// Config holds the signing configuration for a network participant. +// These values come from the simplekeymanager config in your beckn-onix YAML. +type Config struct { + // SubscriberID is the network participant identifier (e.g. "p2p-trading-sandbox1.com"). + SubscriberID string + + // UniqueKeyID is the unique key identifier registered with the Beckn registry. + UniqueKeyID string + + // SigningPrivateKey is the base64-encoded Ed25519 seed (32 bytes). + SigningPrivateKey string + + // ExpiryDuration is how long the signature is valid. Defaults to 5 minutes. + ExpiryDuration time.Duration +} + +// Signer produces Beckn-compatible Authorization headers for JSON payloads. +type Signer struct { + subscriberID string + uniqueKeyID string + privateKey ed25519.PrivateKey + expiry time.Duration +} + +// SignedResult contains the signing output. +type SignedResult struct { + // AuthorizationHeader is the full value for the HTTP Authorization header. + AuthorizationHeader string + + // CreatedAt is the Unix timestamp when the signature was created. + CreatedAt int64 + + // ExpiresAt is the Unix timestamp when the signature expires. + ExpiresAt int64 + + // Signature is the raw base64-encoded Ed25519 signature. + Signature string +} + +// New creates a Signer from the provided config. +func New(cfg Config) (*Signer, error) { + if cfg.SubscriberID == "" { + return nil, fmt.Errorf("signer: SubscriberID is required") + } + if cfg.UniqueKeyID == "" { + return nil, fmt.Errorf("signer: UniqueKeyID is required") + } + if cfg.SigningPrivateKey == "" { + return nil, fmt.Errorf("signer: SigningPrivateKey is required") + } + + seed, err := base64.StdEncoding.DecodeString(cfg.SigningPrivateKey) + if err != nil { + return nil, fmt.Errorf("signer: invalid base64 private key: %w", err) + } + if len(seed) != ed25519.SeedSize { + return nil, fmt.Errorf("signer: private key seed must be %d bytes, got %d", ed25519.SeedSize, len(seed)) + } + + expiry := cfg.ExpiryDuration + if expiry == 0 { + expiry = 5 * time.Minute + } + + return &Signer{ + subscriberID: cfg.SubscriberID, + uniqueKeyID: cfg.UniqueKeyID, + privateKey: ed25519.NewKeyFromSeed(seed), + expiry: expiry, + }, nil +} + +// SignPayload signs a JSON payload and returns the Authorization header value. +func (s *Signer) SignPayload(body []byte) (string, error) { + result, err := s.SignPayloadDetailed(body) + if err != nil { + return "", err + } + return result.AuthorizationHeader, nil +} + +// SignPayloadDetailed signs a JSON payload and returns full signing details. +func (s *Signer) SignPayloadDetailed(body []byte) (*SignedResult, error) { + now := time.Now() + return s.signPayloadAt(body, now) +} + +// signPayloadAt signs at a specific time (used for deterministic testing). +func (s *Signer) signPayloadAt(body []byte, now time.Time) (*SignedResult, error) { + createdAt := now.Unix() + expiresAt := now.Add(s.expiry).Unix() + + signingString, err := buildSigningString(body, createdAt, expiresAt) + if err != nil { + return nil, fmt.Errorf("signer: failed to build signing string: %w", err) + } + + sig := ed25519.Sign(s.privateKey, []byte(signingString)) + sigB64 := base64.StdEncoding.EncodeToString(sig) + + header := fmt.Sprintf( + `Signature keyId="%s|%s|ed25519",algorithm="ed25519",created="%d",expires="%d",headers="(created) (expires) digest",signature="%s"`, + s.subscriberID, s.uniqueKeyID, createdAt, expiresAt, sigB64, + ) + + return &SignedResult{ + AuthorizationHeader: header, + CreatedAt: createdAt, + ExpiresAt: expiresAt, + Signature: sigB64, + }, nil +} + +// buildSigningString creates the canonical string to sign: +// +// (created): {timestamp} +// (expires): {timestamp} +// digest: BLAKE-512={base64_hash} +func buildSigningString(body []byte, createdAt, expiresAt int64) (string, error) { + hasher, err := blake2b.New512(nil) + if err != nil { + return "", err + } + hasher.Write(body) + digest := base64.StdEncoding.EncodeToString(hasher.Sum(nil)) + + return fmt.Sprintf("(created): %d\n(expires): %d\ndigest: BLAKE-512=%s", + createdAt, expiresAt, digest), nil +} diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/signer_test.go b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/signer_test.go new file mode 100644 index 00000000..356b7e6f --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/signer_test.go @@ -0,0 +1,221 @@ +package signer + +import ( + "crypto/ed25519" + "encoding/base64" + "strings" + "testing" + "time" +) + +// Test keys matching the config in local-p2p-bap.yaml (sandbox1). +const ( + testSubscriberID = "p2p-trading-sandbox1.com" + testKeyID = "76EU8aUqHouww7gawT6EibH4bseMCumyDv3sgyXSKENGk8NDcdVwmQ" + testPrivateKey = "Pc6dkYo5LeP0LkwvZXVRV9pcbeh8jDdtdHWymID5cjw=" + testPublicKey = "KVYEWkQB2WwnttVMWfy7KrnqiD51ZDvi8vfCac2IwRE=" +) + +// Sample beckn payload (trimmed confirm request). +var samplePayload = []byte(`{ + "context": { + "version": "2.0.0", + "action": "confirm", + "timestamp": "2024-10-04T10:25:00Z", + "message_id": "msg-confirm-001", + "transaction_id": "txn-energy-001", + "bap_id": "bap.energy-consumer.com", + "bap_uri": "https://bap.energy-consumer.com", + "bpp_id": "bpp.energy-provider.com", + "bpp_uri": "https://bpp.energy-provider.com", + "domain": "beckn.one:deg:p2p-trading:2.0.0" + }, + "message": { + "order": { + "@type": "beckn:Order", + "beckn:orderStatus": "CREATED", + "beckn:seller": "provider-solar-farm-001" + } + } +}`) + +func TestSignAndVerifyRoundTrip(t *testing.T) { + // --- Sign --- + s, err := New(Config{ + SubscriberID: testSubscriberID, + UniqueKeyID: testKeyID, + SigningPrivateKey: testPrivateKey, + }) + if err != nil { + t.Fatalf("New() error: %v", err) + } + + authHeader, err := s.SignPayload(samplePayload) + if err != nil { + t.Fatalf("SignPayload() error: %v", err) + } + + // Basic structure checks + if !strings.HasPrefix(authHeader, "Signature ") { + t.Errorf("expected header to start with 'Signature ', got: %s", authHeader) + } + if !strings.Contains(authHeader, testSubscriberID+"|"+testKeyID+"|ed25519") { + t.Errorf("keyId not found in header: %s", authHeader) + } + if !strings.Contains(authHeader, `algorithm="ed25519"`) { + t.Errorf("algorithm not found in header: %s", authHeader) + } + + t.Logf("Authorization: %s", authHeader) + + // --- Verify --- + err = Verify(samplePayload, authHeader, testPublicKey) + if err != nil { + t.Fatalf("Verify() error: %v", err) + } +} + +func TestSignPayloadDetailed(t *testing.T) { + s, err := New(Config{ + SubscriberID: testSubscriberID, + UniqueKeyID: testKeyID, + SigningPrivateKey: testPrivateKey, + }) + if err != nil { + t.Fatalf("New() error: %v", err) + } + + result, err := s.SignPayloadDetailed(samplePayload) + if err != nil { + t.Fatalf("SignPayloadDetailed() error: %v", err) + } + + if result.ExpiresAt-result.CreatedAt != 300 { + t.Errorf("expected 300s expiry window, got %d", result.ExpiresAt-result.CreatedAt) + } + if result.Signature == "" { + t.Error("expected non-empty signature") + } + if result.AuthorizationHeader == "" { + t.Error("expected non-empty auth header") + } +} + +func TestVerifyRejectsTamperedPayload(t *testing.T) { + s, err := New(Config{ + SubscriberID: testSubscriberID, + UniqueKeyID: testKeyID, + SigningPrivateKey: testPrivateKey, + }) + if err != nil { + t.Fatalf("New() error: %v", err) + } + + authHeader, err := s.SignPayload(samplePayload) + if err != nil { + t.Fatalf("SignPayload() error: %v", err) + } + + // Tamper with payload + tampered := append([]byte{}, samplePayload...) + tampered[10] = 'X' + + err = Verify(tampered, authHeader, testPublicKey) + if err == nil { + t.Fatal("expected verification to fail for tampered payload") + } +} + +func TestVerifyRejectsExpiredSignature(t *testing.T) { + s, err := New(Config{ + SubscriberID: testSubscriberID, + UniqueKeyID: testKeyID, + SigningPrivateKey: testPrivateKey, + ExpiryDuration: 1 * time.Second, + }) + if err != nil { + t.Fatalf("New() error: %v", err) + } + + // Sign at a time in the past + pastTime := time.Now().Add(-10 * time.Minute) + result, err := s.signPayloadAt(samplePayload, pastTime) + if err != nil { + t.Fatalf("signPayloadAt() error: %v", err) + } + + err = Verify(samplePayload, result.AuthorizationHeader, testPublicKey) + if err == nil { + t.Fatal("expected verification to fail for expired signature") + } + if !strings.Contains(err.Error(), "expired") { + t.Errorf("expected 'expired' in error, got: %v", err) + } +} + +func TestVerifyRejectsWrongPublicKey(t *testing.T) { + s, err := New(Config{ + SubscriberID: testSubscriberID, + UniqueKeyID: testKeyID, + SigningPrivateKey: testPrivateKey, + }) + if err != nil { + t.Fatalf("New() error: %v", err) + } + + authHeader, err := s.SignPayload(samplePayload) + if err != nil { + t.Fatalf("SignPayload() error: %v", err) + } + + // Use a different key pair + _, wrongPriv, _ := ed25519.GenerateKey(nil) + wrongPub := wrongPriv.Public().(ed25519.PublicKey) + wrongPubB64 := base64.StdEncoding.EncodeToString(wrongPub) + + err = Verify(samplePayload, authHeader, wrongPubB64) + if err == nil { + t.Fatal("expected verification to fail for wrong public key") + } +} + +func TestNewValidatesConfig(t *testing.T) { + tests := []struct { + name string + cfg Config + want string + }{ + {"missing subscriber", Config{UniqueKeyID: "k", SigningPrivateKey: testPrivateKey}, "SubscriberID"}, + {"missing keyID", Config{SubscriberID: "s", SigningPrivateKey: testPrivateKey}, "UniqueKeyID"}, + {"missing private key", Config{SubscriberID: "s", UniqueKeyID: "k"}, "SigningPrivateKey"}, + {"bad base64", Config{SubscriberID: "s", UniqueKeyID: "k", SigningPrivateKey: "not-base64!!!"}, "invalid base64"}, + {"wrong key size", Config{SubscriberID: "s", UniqueKeyID: "k", SigningPrivateKey: base64.StdEncoding.EncodeToString([]byte("short"))}, "must be 32 bytes"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := New(tt.cfg) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), tt.want) { + t.Errorf("expected error containing %q, got: %v", tt.want, err) + } + }) + } +} + +func TestParseKeyID(t *testing.T) { + sub, key, alg, err := ParseKeyID("p2p-trading-sandbox1.com|76EU8aUq|ed25519") + if err != nil { + t.Fatalf("ParseKeyID() error: %v", err) + } + if sub != "p2p-trading-sandbox1.com" || key != "76EU8aUq" || alg != "ed25519" { + t.Errorf("unexpected result: %s, %s, %s", sub, key, alg) + } + + _, _, _, err = ParseKeyID("bad-format") + if err == nil { + t.Fatal("expected error for bad format") + } +} diff --git a/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/verifier.go b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/verifier.go new file mode 100644 index 00000000..71d1a721 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/discom-signing-kit/golang/verifier.go @@ -0,0 +1,100 @@ +package signer + +import ( + "crypto/ed25519" + "encoding/base64" + "fmt" + "strconv" + "strings" + "time" +) + +// Verify checks that an Authorization header is a valid signature for the given body, +// using the sender's base64-encoded public key. Returns nil if valid. +func Verify(body []byte, authHeader string, publicKeyBase64 string) error { + return VerifyAt(body, authHeader, publicKeyBase64, time.Now()) +} + +// VerifyAt checks validity at a specific time (useful for testing). +func VerifyAt(body []byte, authHeader string, publicKeyBase64 string, now time.Time) error { + created, expires, sig, err := parseAuthHeader(authHeader) + if err != nil { + return fmt.Errorf("verifier: %w", err) + } + + currentTime := now.Unix() + if created > currentTime { + return fmt.Errorf("verifier: signature not yet valid (created %d > now %d)", created, currentTime) + } + if currentTime > expires { + return fmt.Errorf("verifier: signature expired (expires %d < now %d)", expires, currentTime) + } + + sigBytes, err := base64.StdEncoding.DecodeString(sig) + if err != nil { + return fmt.Errorf("verifier: invalid signature base64: %w", err) + } + + signingString, err := buildSigningString(body, created, expires) + if err != nil { + return fmt.Errorf("verifier: %w", err) + } + + pubKeyBytes, err := base64.StdEncoding.DecodeString(publicKeyBase64) + if err != nil { + return fmt.Errorf("verifier: invalid public key base64: %w", err) + } + + if !ed25519.Verify(ed25519.PublicKey(pubKeyBytes), []byte(signingString), sigBytes) { + return fmt.Errorf("verifier: signature verification failed") + } + + return nil +} + +// ParseKeyID extracts subscriberID, uniqueKeyID, and algorithm from a keyId field. +// Format: "subscriber_id|unique_key_id|algorithm" +func ParseKeyID(keyID string) (subscriberID, uniqueKeyID, algorithm string, err error) { + parts := strings.Split(keyID, "|") + if len(parts) != 3 { + return "", "", "", fmt.Errorf("invalid keyId format, expected 'subscriber|keyId|algorithm', got %q", keyID) + } + return parts[0], parts[1], parts[2], nil +} + +func parseAuthHeader(header string) (created, expires int64, signature string, err error) { + header = strings.TrimPrefix(header, "Signature ") + + params := make(map[string]string) + for _, part := range strings.Split(header, ",") { + kv := strings.SplitN(strings.TrimSpace(part), "=", 2) + if len(kv) == 2 { + params[strings.TrimSpace(kv[0])] = strings.Trim(kv[1], `"`) + } + } + + createdStr, ok := params["created"] + if !ok { + return 0, 0, "", fmt.Errorf("missing 'created' in auth header") + } + created, err = strconv.ParseInt(createdStr, 10, 64) + if err != nil { + return 0, 0, "", fmt.Errorf("invalid 'created' timestamp: %w", err) + } + + expiresStr, ok := params["expires"] + if !ok { + return 0, 0, "", fmt.Errorf("missing 'expires' in auth header") + } + expires, err = strconv.ParseInt(expiresStr, 10, 64) + if err != nil { + return 0, 0, "", fmt.Errorf("invalid 'expires' timestamp: %w", err) + } + + signature, ok = params["signature"] + if !ok { + return 0, 0, "", fmt.Errorf("missing 'signature' in auth header") + } + + return created, expires, signature, nil +} diff --git a/testnet/p2p-trading-interdiscom-devkit/install/docker-compose-adapter-p2p.yml b/testnet/p2p-trading-interdiscom-devkit/install/docker-compose-adapter-p2p.yml new file mode 100644 index 00000000..058a8ea0 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/install/docker-compose-adapter-p2p.yml @@ -0,0 +1,146 @@ +services: + # ============================================ + # Core Infrastructure Services + # ============================================ + + # Redis - Caching Service + redis: + image: redis:alpine + container_name: redis + ports: + - "6379:6379" + networks: + - beckn_network + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 5 + + onix-bap: + image: fidedocker/onix-adapter-deg:p2p-multiarch-v4 + container_name: onix-bap + networks: + - beckn_network + ports: + - "8081:8081" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-p2p-bap.yaml"] + + onix-bpp: + image: fidedocker/onix-adapter-deg:p2p-multiarch-v4 + container_name: onix-bpp + networks: + - beckn_network + ports: + - "8082:8082" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-p2p-bpp.yaml"] + + onix-utilitybpp: + image: fidedocker/onix-adapter-deg:p2p-multiarch-v4 + pull_policy: never + container_name: onix-utilitybpp + networks: + - beckn_network + ports: + - "8083:8083" + environment: + CONFIG_FILE: "/app/config/local-simple.yaml" + VAULT_ADDR: http://vault:8200 + VAULT_TOKEN: root + REDIS_ADDR: redis:6379 + RABBITMQ_ADDR: rabbitmq:5672 + RABBITMQ_USER: admin + RABBITMQ_PASS: admin123 + volumes: + - ../config:/app/config + - ../schemas:/app/schemas + command: ["./server", "--config=/app/config/local-p2p-utilitybpp.yaml"] + + sandbox-bap: + container_name: sandbox-bap + + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + + environment: + - NODE_ENV=production + - PORT=3001 + ports: + - "3001:3001" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3001/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_network + + sandbox-bpp: + container_name: sandbox-bpp + + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + + environment: + - NODE_ENV=production + - PORT=3002 + - PERSONA=bpp # bpp persona + ports: + - "3002:3002" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3002/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_network + + sandbox-utilitybpp: + container_name: sandbox-utilitybpp + + image: fidedocker/sandbox-2.0:latest + platform: linux/amd64 + + environment: + - NODE_ENV=production + - PORT=3003 + - PERSONA=utility-bpp # utility-bpp persona + ports: + - "3003:3003" + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost:3003/api/health"] + interval: 10s + timeout: 3s + retries: 5 + start_period: 10s + networks: + - beckn_network + +networks: + beckn_network: + name: beckn_network + driver: bridge diff --git a/testnet/p2p-trading-interdiscom-devkit/postman/22-01-26-Bootcamp-IES_Energy_Verifiable_Credentials.postman_collection b/testnet/p2p-trading-interdiscom-devkit/postman/22-01-26-Bootcamp-IES_Energy_Verifiable_Credentials.postman_collection new file mode 100644 index 00000000..abb9f1e1 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/postman/22-01-26-Bootcamp-IES_Energy_Verifiable_Credentials.postman_collection @@ -0,0 +1,318 @@ +{ + "info": { + "_postman_id": "12efb445-22d5-40fd-ba9e-46f2a0135721", + "name": "22/01/26-Bootcamp-IES Energy Verifiable Credentials", + "description": "Complete Postman collection for IES Energy Verifiable Credentials with proper JSON-LD contexts hosted on GitHub Pages.\n\nIncludes:\n- Consumption Profile VC\n- Utility Customer VC\n- Generation Profile VC\n- Storage Profile VC\n\n**Features:**\n- Schema creation\n- Template creation (for PDF/QR rendering)\n- Credential issuance\n- Get credential (JSON & PDF)\n- Verification\n- Revocation\n\n**Context Files:** https://github.com/Anusree-J/vc_context/tree/main/energy\n\n**Tested and Verified:** All credentials successfully issue and verify against the SunbirdRC credential service.", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "45350824", + "_collection_link": "https://go.postman.co/collection/45350824-12efb445-22d5-40fd-ba9e-46f2a0135721?source=collection_link" + }, + "item": [ + { + "name": "Verification endpoints", + "item": [ + { + "name": "Get Consumption Profile Credential (JSON)", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Credential retrieved successfully\", function () {", + " pm.response.to.have.status(200);", + " let jsonData = pm.response.json();", + " pm.expect(jsonData.type).to.include(\"ConsumptionProfileCredential\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{beckn_credentials_host}}/credential/credentials/{{consumption_credential_id}}", + "host": [ + "{{beckn_credentials_host}}" + ], + "path": [ + "credential", + "credentials", + "{{consumption_credential_id}}" + ] + }, + "description": "Retrieves the issued Consumption Profile Credential as JSON." + }, + "response": [] + }, + { + "name": "Get Utility Customer Credential (JSON)", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Credential retrieved successfully\", function () {", + " pm.response.to.have.status(200);", + " let jsonData = pm.response.json();", + " pm.expect(jsonData.type).to.include(\"UtilityCustomerCredential\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{beckn_credentials_host}}/credential/credentials/{{utility_customer_credential_id}}", + "host": [ + "{{beckn_credentials_host}}" + ], + "path": [ + "credential", + "credentials", + "{{utility_customer_credential_id}}" + ] + }, + "description": "Retrieves the issued Utility Customer Credential as JSON." + }, + "response": [] + }, + { + "name": "Get Generation Profile Credential (JSON)", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Credential retrieved successfully\", function () {", + " pm.response.to.have.status(200);", + " let jsonData = pm.response.json();", + " pm.expect(jsonData.type).to.include(\"GenerationProfileCredential\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{beckn_credentials_host}}/credential/credentials/{{generation_credential_id}}", + "host": [ + "{{beckn_credentials_host}}" + ], + "path": [ + "credential", + "credentials", + "{{generation_credential_id}}" + ] + }, + "description": "Retrieves the issued Generation Profile Credential as JSON." + }, + "response": [] + }, + { + "name": "Get Storage Profile Credential (JSON)", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Credential retrieved successfully\", function () {", + " pm.response.to.have.status(200);", + " let jsonData = pm.response.json();", + " pm.expect(jsonData.type).to.include(\"StorageProfileCredential\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "accept": true + } + }, + "request": { + "method": "GET", + "header": [ + { + "key": "Accept", + "value": "application/json", + "type": "text" + } + ], + "url": { + "raw": "{{beckn_credentials_host}}/credential/credentials/{{storage_credential_id}}", + "host": [ + "{{beckn_credentials_host}}" + ], + "path": [ + "credential", + "credentials", + "{{storage_credential_id}}" + ] + }, + "description": "Retrieves the issued Storage Profile Credential as JSON." + }, + "response": [] + }, + { + "name": "Verify Consumption Profile Credential", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Credential verification successful\", function () {", + " pm.response.to.have.status(200);", + " let jsonData = pm.response.json();", + " pm.expect(jsonData.status).to.eql(\"ISSUED\");", + " pm.expect(jsonData.checks[0].proof).to.eql(\"OK\");", + " pm.expect(jsonData.checks[0].revoked).to.eql(\"OK\");", + " pm.expect(jsonData.checks[0].expired).to.eql(\"OK\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{beckn_credentials_host}}/credential/credentials/{{consumption_credential_id}}/verify", + "host": [ + "{{beckn_credentials_host}}" + ], + "path": [ + "credential", + "credentials", + "{{consumption_credential_id}}", + "verify" + ] + }, + "description": "Verifies the Consumption Profile Credential." + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "beckn_credentials_host", + "value": "http://35.244.45.209" + }, + { + "key": "issuer_did", + "value": "" + }, + { + "key": "consumption_schema_id", + "value": "" + }, + { + "key": "consumption_template_id", + "value": "" + }, + { + "key": "consumption_credential_id", + "value": "" + }, + { + "key": "utility_customer_schema_id", + "value": "" + }, + { + "key": "utility_customer_template_id", + "value": "" + }, + { + "key": "utility_customer_credential_id", + "value": "" + }, + { + "key": "generation_schema_id", + "value": "" + }, + { + "key": "generation_template_id", + "value": "" + }, + { + "key": "generation_credential_id", + "value": "" + }, + { + "key": "storage_schema_id", + "value": "" + }, + { + "key": "storage_template_id", + "value": "" + }, + { + "key": "storage_credential_id", + "value": "" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:BAP-DEG.postman_collection.json b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:BAP-DEG.postman_collection.json new file mode 100644 index 00000000..f4ec774c --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:BAP-DEG.postman_collection.json @@ -0,0 +1,277 @@ +{ + "info": { + "_postman_id": "83b7e008-32eb-41fa-b4a1-d5ec74dae1e4", + "name": "p2p-trading-interdiscom:BAP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Buyer Application Platform implementing p2p-trading-interdiscom APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "confirm", + "item": [ + { + "name": "cascaded-confirm-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-cascaded-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 2.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"AUTHORIZED\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"p2pTrading-bpp.com\",\n \"accountHolderName\": \"P2P Trading Platform Pvt Ltd\",\n \"accountNumber\": \"5555666677\",\n \"ifscCode\": \"SBIN0001234\",\n \"bankName\": \"State Bank of India\",\n \"vpa\": \"p2p-trading@upi\"\n },\n {\n \"beneficiaryId\": \"example-transmission-bpp.com\",\n \"accountHolderName\": \"Transmission Utility Provider Pvt Ltd\",\n \"accountNumber\": \"8888999900\",\n \"ifscCode\": \"AXIS0004567\",\n \"bankName\": \"Axis Bank\",\n \"vpa\": \"transmission-utility@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/confirm", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: cascaded-confirm-request" + }, + "response": [] + }, + { + "name": "confirm-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": {\n \"unitQuantity\": 25.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"AUTHORIZED\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/confirm", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: confirm-request" + }, + "response": [] + } + ] + }, + { + "name": "discover", + "item": [ + { + "name": "discover-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\",\n \"location\": {\n \"city\": {\n \"code\": \"BLR\",\n \"name\": \"Bangalore\"\n },\n \"country\": {\n \"code\": \"IND\",\n \"name\": \"India\"\n }\n },\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\"\n ]\n },\n \"message\": {\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?('p2p-interdiscom-trading-pilot-network' == @.beckn:networkId && @.beckn:provider.beckn:providerAttributes.utilityId == 'TPDDL-DL')]\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/discover", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "discover" + ] + }, + "description": "Discover request: discover-request" + }, + "response": [] + } + ] + }, + { + "name": "init", + "item": [ + { + "name": "cascaded-init-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-cascaded-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 2.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"INITIATED\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"p2pTrading-bpp.com\",\n \"accountHolderName\": \"P2P Trading Platform Pvt Ltd\",\n \"accountNumber\": \"5555666677\",\n \"ifscCode\": \"SBIN0001234\",\n \"bankName\": \"State Bank of India\",\n \"vpa\": \"p2p-trading@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: cascaded-init-request" + }, + "response": [] + }, + { + "name": "init-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": {\n \"unitQuantity\": 25.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"INITIATED\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"bap.energy-consumer.com\",\n \"accountHolderName\": \"Energy Consumer BAP Pvt Ltd\",\n \"accountNumber\": \"1234567890\",\n \"ifscCode\": \"HDFC0001234\",\n \"bankName\": \"HDFC Bank\",\n \"vpa\": \"energy-consumer@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/init", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: init-request" + }, + "response": [] + } + ] + }, + { + "name": "select", + "item": [ + { + "name": "select-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"select\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": {\n \"unitQuantity\": 25.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/select", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "select" + ] + }, + "description": "Select request: select-request" + }, + "response": [] + } + ] + }, + { + "name": "status", + "item": [ + { + "name": "status-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"beckn:id\": \"order-energy-001\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bap_adapter_url}}/status", + "host": [ + "{{bap_adapter_url}}" + ], + "path": [ + "status" + ] + }, + "description": "Status request: status-request" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-trading-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-trading-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bap_adapter_url", + "value": "http://localhost:8081/bap/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:BPP-DEG.postman_collection.json b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:BPP-DEG.postman_collection.json new file mode 100644 index 00000000..74642e52 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:BPP-DEG.postman_collection.json @@ -0,0 +1,449 @@ +{ + "info": { + "_postman_id": "5349ac7f-b63e-48e0-97ca-c84fecca6909", + "name": "p2p-trading-interdiscom:BPP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Buyer Provider Platform implementing p2p-trading-interdiscom APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "on_confirm", + "item": [ + { + "name": "confirm-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": {\n \"unitQuantity\": 25.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"AUTHORIZED\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_confirm" + ] + }, + "description": "On_confirm request: confirm-response" + }, + "response": [] + } + ] + }, + { + "name": "on_discover", + "item": [ + { + "name": "discover-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_discover\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"catalogs\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Catalog\",\n \"beckn:id\": \"catalog-energy-001\",\n \"beckn:bppId\": \"bpp.energy-provider.com\",\n \"beckn:bppUri\": \"https://bpp.energy-provider.com\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Trading Catalog\"\n },\n \"beckn:items\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-interdiscom-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 30.5 kWh\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n },\n \"beckn:providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/100200300\",\n \"utilityId\": \"TPDDL-DL\",\n \"utilityCustomerId\": \"TPDDL-CUST-001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"meterId\": \"der://meter/100200300\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer - 6am-12pm\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer - 12pm-6pm\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_discover", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_discover" + ] + }, + "description": "On_discover request: discover-response" + }, + "response": [] + } + ] + }, + { + "name": "on_init", + "item": [ + { + "name": "init-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": {\n \"unitQuantity\": 25.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"USD\",\n \"value\": 4.25,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 4.05,\n \"currency\": \"USD\",\n \"description\": \"Energy value (15 kWh \\u00d7 $0.15 + 10 kWh \\u00d7 $0.18)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.08,\n \"currency\": \"USD\",\n \"description\": \"Buyer platform fee (2%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.12,\n \"currency\": \"USD\",\n \"description\": \"Seller platform fee (3%)\"\n }\n ]\n },\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:acceptedPaymentMethod\": [\n \"UPI\",\n \"BANK_TRANSFER\",\n \"WALLET\"\n ],\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"AUTHORIZED\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"bap.energy-consumer.com\",\n \"accountHolderName\": \"Energy Consumer BAP Pvt Ltd\",\n \"accountNumber\": \"1234567890\",\n \"ifscCode\": \"HDFC0001234\",\n \"bankName\": \"HDFC Bank\",\n \"vpa\": \"energy-consumer@upi\"\n },\n {\n \"beneficiaryId\": \"bpp.energy-provider.com\",\n \"accountHolderName\": \"Solar Farm Energy Provider Pvt Ltd\",\n \"accountNumber\": \"9876543210\",\n \"ifscCode\": \"ICICI0005678\",\n \"bankName\": \"ICICI Bank\",\n \"vpa\": \"solar-provider@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_init" + ] + }, + "description": "On_init request: init-response" + }, + "response": [] + } + ] + }, + { + "name": "on_select", + "item": [ + { + "name": "select-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_select\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"bap.energy-consumer.com\",\n \"bpp_id\": \"bpp.energy-provider.com\",\n \"total_quantity\": {\n \"unitQuantity\": 25.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderValue\": {\n \"currency\": \"USD\",\n \"value\": 4.25,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 4.05,\n \"currency\": \"USD\",\n \"description\": \"Energy value (15 kWh \\u00d7 $0.15 + 10 kWh \\u00d7 $0.18)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.08,\n \"currency\": \"USD\",\n \"description\": \"Buyer platform fee (2%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.12,\n \"currency\": \"USD\",\n \"description\": \"Seller platform fee (3%)\"\n }\n ]\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:paymentStatus\": \"PENDING\",\n \"beckn:acceptedPaymentMethod\": [\n \"UPI\",\n \"BANK_TRANSFER\",\n \"WALLET\"\n ]\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_select", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_select" + ] + }, + "description": "On_select request: select-response" + }, + "response": [] + } + ] + }, + { + "name": "on_status", + "item": [ + { + "name": "status-response-completed", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"COMPLETED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 15.0,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T09:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 7.5,\n \"allocatedEnergy\": 7.5,\n \"unit\": \"kWh\"\n },\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T09:00:00Z\",\n \"schema:endTime\": \"2024-10-04T12:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 7.5,\n \"allocatedEnergy\": 7.5,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T12:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 10.0,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T12:00:00Z\",\n \"schema:endTime\": \"2024-10-04T15:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 5.0,\n \"allocatedEnergy\": 5.0,\n \"unit\": \"kWh\"\n },\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T15:00:00Z\",\n \"schema:endTime\": \"2024-10-04T18:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 5.0,\n \"allocatedEnergy\": 5.0,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T18:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"USD\",\n \"value\": 4.25,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 4.05,\n \"currency\": \"USD\",\n \"description\": \"Energy value (15 kWh \\u00d7 $0.15 + 10 kWh \\u00d7 $0.18)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.08,\n \"currency\": \"USD\",\n \"description\": \"Buyer platform fee (2%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.12,\n \"currency\": \"USD\",\n \"description\": \"Seller platform fee (3%)\"\n }\n ]\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"SETTLED\",\n \"beckn:paidAt\": \"2024-10-04T19:00:00Z\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_status", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_status" + ] + }, + "description": "On_status request: status-response-completed" + }, + "response": [] + }, + { + "name": "status-response-curtailed", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"PARTIALLYFULFILLED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 10.0,\n \"curtailedQuantity\": 5.0,\n \"curtailmentReason\": \"GRID_OUTAGE\",\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T14:30:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 10.0,\n \"allocatedEnergy\": 10.0,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T14:30:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"FAILED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 0.0,\n \"curtailedQuantity\": 10.0,\n \"curtailmentReason\": \"GRID_OUTAGE\",\n \"meterReadings\": [],\n \"lastUpdated\": \"2024-10-04T14:30:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 1.5\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"COMPLETED\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"bap.energy-consumer.com\",\n \"accountHolderName\": \"Energy Consumer BAP Pvt Ltd\",\n \"accountNumber\": \"1234567890\",\n \"ifscCode\": \"HDFC0001234\",\n \"bankName\": \"HDFC Bank\",\n \"vpa\": \"energy-consumer@upi\"\n },\n {\n \"beneficiaryId\": \"bpp.energy-provider.com\",\n \"accountHolderName\": \"Solar Farm Energy Provider Pvt Ltd\",\n \"accountNumber\": \"9876543210\",\n \"ifscCode\": \"ICICI0005678\",\n \"bankName\": \"ICICI Bank\",\n \"vpa\": \"solar-provider@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_status", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_status" + ] + }, + "description": "On_status request: status-response-curtailed" + }, + "response": [] + }, + { + "name": "status-response", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"IN_PROGRESS\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 7.5,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T09:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 7.5,\n \"allocatedEnergy\": 7.5,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T15:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"PENDING\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 0.0,\n \"meterReadings\": [],\n \"lastUpdated\": \"2024-10-04T15:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"AUTHORIZED\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_status", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_status" + ] + }, + "description": "On_status request: status-response" + }, + "response": [] + } + ] + }, + { + "name": "on_update", + "item": [ + { + "name": "on-update-response-curtailment", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_update\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"INPROGRESS\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"IN_PROGRESS\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 8.5,\n \"curtailedQuantity\": 6.5,\n \"curtailmentReason\": \"GRID_OUTAGE\",\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T12:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 8.5,\n \"allocatedEnergy\": 8.5,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T14:30:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"USD\",\n \"value\": 1.36,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 1.28,\n \"currency\": \"USD\",\n \"description\": \"Energy value for delivered quantity (8.5 kWh \\u00d7 $0.15)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.03,\n \"currency\": \"USD\",\n \"description\": \"Buyer platform fee (2%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.04,\n \"currency\": \"USD\",\n \"description\": \"Seller platform fee (3%)\"\n }\n ]\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 1.36\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"ADJUSTED\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_update", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_update" + ] + }, + "description": "On_update request: on-update-response-curtailment" + }, + "response": [] + }, + { + "name": "on-update-response-final-invoice", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_update\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"INPROGRESS\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 15.0,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T06:00:00Z\",\n \"schema:endTime\": \"2024-10-04T12:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 15.0,\n \"allocatedEnergy\": 15.0,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T18:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n },\n \"fulfillmentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 10.0,\n \"meterReadings\": [\n {\n \"beckn:timeWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T12:00:00Z\",\n \"schema:endTime\": \"2024-10-04T18:00:00Z\"\n },\n \"consumedEnergy\": 0.0,\n \"producedEnergy\": 10.0,\n \"allocatedEnergy\": 10.0,\n \"unit\": \"kWh\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T18:00:00Z\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.18,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T12:00:00Z\",\n \"schema:endTime\": \"2026-01-09T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T11:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"USD\",\n \"value\": 4.25,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 4.05,\n \"currency\": \"USD\",\n \"description\": \"Energy value (15 kWh \\u00d7 $0.15 + 10 kWh \\u00d7 $0.18)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.08,\n \"currency\": \"USD\",\n \"description\": \"Buyer platform fee (2%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.12,\n \"currency\": \"USD\",\n \"description\": \"Seller platform fee (3%)\"\n }\n ]\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"AUTHORIZED\",\n \"beckn:acceptedPaymentMethod\": [\n \"UPI\",\n \"BANK_TRANSFER\"\n ],\n \"beckn:paymentURL\": \"https://payments.seller-platform.com/track?txn=TXN-ENERGY-001\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"bpp.energy-provider.com\",\n \"accountHolderName\": \"Solar Farm Energy Provider Pvt Ltd\",\n \"accountNumber\": \"9876543210\",\n \"ifscCode\": \"ICICI0005678\",\n \"bankName\": \"ICICI Bank\",\n \"vpa\": \"solar-provider@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_update", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_update" + ] + }, + "description": "On_update request: on-update-response-final-invoice" + }, + "response": [] + }, + { + "name": "on-update-response-settlement-complete", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_update\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:orderStatus\": \"COMPLETED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ]\n }\n },\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 10.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-afternoon-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Afternoon Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ]\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"USD\",\n \"value\": 4.25,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 4.05,\n \"currency\": \"USD\",\n \"description\": \"Energy value (15 kWh \\u00d7 $0.15 + 10 kWh \\u00d7 $0.18)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.08,\n \"currency\": \"USD\",\n \"description\": \"Buyer platform fee (2%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 0.12,\n \"currency\": \"USD\",\n \"description\": \"Seller platform fee (3%)\"\n }\n ]\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 4.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"SETTLED\",\n \"beckn:paidAt\": \"2024-10-04T18:40:00Z\",\n \"beckn:txnRef\": \"TXN-ENERGY-001-SETTLED\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/on_update", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "on_update" + ] + }, + "description": "On_update request: on-update-response-settlement-complete" + }, + "response": [] + } + ] + }, + { + "name": "publish", + "item": [ + { + "name": "publish-catalog", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"catalog_publish\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"catalogs\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Catalog\",\n \"beckn:id\": \"catalog-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Trading Catalog\"\n },\n \"beckn:bppId\": \"bpp.energy-provider.com\",\n \"beckn:bppUri\": \"https://bpp.energy-provider.com\",\n \"beckn:items\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-interdiscom-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 30.5 kWh\",\n \"beckn:shortDesc\": \"Carbon Offset Certified Solar Energy\",\n \"beckn:longDesc\": \"High-quality solar energy from verified source with carbon offset certification\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n },\n \"beckn:providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/100200300\",\n \"utilityId\": \"TPDDL-DL\",\n \"utilityCustomerId\": \"TPDDL-CUST-001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"meterId\": \"der://meter/100200300\"\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-interdiscom-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 50.0 kWh\",\n \"beckn:shortDesc\": \"Standard Solar Energy\",\n \"beckn:longDesc\": \"Reliable solar energy from verified source\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n },\n \"beckn:providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/100200301\",\n \"utilityId\": \"TPDDL-DL\",\n \"utilityCustomerId\": \"TPDDL-CUST-001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"meterId\": \"der://meter/100200301\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Offer - Morning Slot\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 30.5,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T10:00:00Z\",\n \"schema:endTime\": \"2024-10-04T14:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-04T09:00:00Z\"\n }\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Offer - Afternoon Slot\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-002\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.12,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 50.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T14:00:00Z\",\n \"schema:endTime\": \"2024-10-04T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-04T13:00:00Z\"\n }\n }\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/publish", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "publish" + ] + }, + "description": "Publish request: publish-catalog" + }, + "response": [] + }, + { + "name": "publish-reduce-catalog-inventory", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"catalog_publish\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"catalogs\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Catalog\",\n \"beckn:id\": \"catalog-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Trading Catalog\"\n },\n \"beckn:bppId\": \"bpp.energy-provider.com\",\n \"beckn:bppUri\": \"https://bpp.energy-provider.com\",\n \"beckn:isActive\": true,\n \"beckn:items\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-interdiscom-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 3.5 kWh\",\n \"beckn:shortDesc\": \"Carbon Offset Certified Solar Energy\",\n \"beckn:longDesc\": \"High-quality solar energy from verified source with carbon offset certification\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n },\n \"beckn:providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/100200300\",\n \"utilityId\": \"TPDDL-DL\",\n \"utilityCustomerId\": \"TPDDL-CUST-001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"meterId\": \"der://meter/100200300\"\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-interdiscom-trading-pilot-network\"\n ],\n \"beckn:isActive\": true,\n \"beckn:id\": \"energy-resource-solar-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 50.0 kWh\",\n \"beckn:shortDesc\": \"Standard Solar Energy\",\n \"beckn:longDesc\": \"Reliable solar energy from verified source\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n },\n \"beckn:providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/100200301\",\n \"utilityId\": \"TPDDL-DL\",\n \"utilityCustomerId\": \"TPDDL-CUST-001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"meterId\": \"der://meter/100200301\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Daily Settlement Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 15.5,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T10:00:00Z\",\n \"schema:endTime\": \"2024-10-04T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-04T23:59:59Z\"\n }\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Bulk Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-002\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.12,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 25.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T08:00:00Z\",\n \"schema:endTime\": \"2024-10-04T16:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-11T23:59:59Z\"\n }\n }\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/publish", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "publish" + ] + }, + "description": "Publish request: publish-reduce-catalog-inventory" + }, + "response": [] + }, + { + "name": "publish-revoke-catalog", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"catalog_publish\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"catalogs\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Catalog\",\n \"beckn:id\": \"catalog-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Trading Catalog\"\n },\n \"beckn:bppId\": \"bpp.energy-provider.com\",\n \"beckn:bppUri\": \"https://bpp.energy-provider.com\",\n \"beckn:isActive\": false,\n \"beckn:items\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-interdiscom-trading-pilot-network\"\n ],\n \"beckn:id\": \"energy-resource-solar-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 30.5 kWh\",\n \"beckn:shortDesc\": \"Carbon Offset Certified Solar Energy\",\n \"beckn:longDesc\": \"High-quality solar energy from verified source with carbon offset certification\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n },\n \"beckn:providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/100200300\",\n \"utilityId\": \"TPDDL-DL\",\n \"utilityCustomerId\": \"TPDDL-CUST-001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"meterId\": \"der://meter/100200300\"\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:networkId\": [\n \"p2p-interdiscom-trading-pilot-network\"\n ],\n \"beckn:id\": \"energy-resource-solar-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 50.0 kWh\",\n \"beckn:shortDesc\": \"Standard Solar Energy\",\n \"beckn:longDesc\": \"Reliable solar energy from verified source\"\n },\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Farm 001\"\n },\n \"beckn:providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/100200301\",\n \"utilityId\": \"TPDDL-DL\",\n \"utilityCustomerId\": \"TPDDL-CUST-001\"\n }\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"meterId\": \"der://meter/100200301\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Daily Settlement Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 30.5,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T10:00:00Z\",\n \"schema:endTime\": \"2024-10-04T18:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-04T23:59:59Z\"\n }\n }\n },\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-002\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Bulk Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-002\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.12,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 50.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T08:00:00Z\",\n \"schema:endTime\": \"2024-10-04T16:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2024-10-04T00:00:00Z\",\n \"schema:endTime\": \"2024-10-11T23:59:59Z\"\n }\n }\n }\n ]\n }\n ]\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/publish", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "publish" + ] + }, + "description": "Publish request: publish-revoke-catalog" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-trading-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-trading-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bpp_adapter_url", + "value": "http://localhost:8082/bpp/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:UtilityBPP-DEG.postman_collection.json b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:UtilityBPP-DEG.postman_collection.json new file mode 100644 index 00000000..4477948c --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:UtilityBPP-DEG.postman_collection.json @@ -0,0 +1,131 @@ +{ + "info": { + "_postman_id": "b25fa2d7-2e05-4555-a3d3-a6fa85748a20", + "name": "p2p-trading-interdiscom:UtilityBPP-DEG", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "description": "Postman collection for Utility BPP (Transmission/Grid Provider Platform) implementing p2p-trading-interdiscom APIs based on Beckn Protocol v2" + }, + "item": [ + { + "name": "confirm", + "item": [ + { + "name": "cascaded-confirm-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-cascaded-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 2.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"AUTHORIZED\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"p2pTrading-bpp.com\",\n \"accountHolderName\": \"P2P Trading Platform Pvt Ltd\",\n \"accountNumber\": \"5555666677\",\n \"ifscCode\": \"SBIN0001234\",\n \"bankName\": \"State Bank of India\",\n \"vpa\": \"p2p-trading@upi\"\n },\n {\n \"beneficiaryId\": \"example-transmission-bpp.com\",\n \"accountHolderName\": \"Transmission Utility Provider Pvt Ltd\",\n \"accountNumber\": \"8888999900\",\n \"ifscCode\": \"AXIS0004567\",\n \"bankName\": \"Axis Bank\",\n \"vpa\": \"transmission-utility@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/confirm", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "confirm" + ] + }, + "description": "Confirm request: cascaded-confirm-request" + }, + "response": [] + } + ] + }, + { + "name": "init", + "item": [ + { + "name": "cascaded-init-request", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"provider-solar-farm-001\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"buyer-001\",\n \"beckn:buyerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOrder\",\n \"bap_id\": \"p2pTrading-bpp.com\",\n \"bpp_id\": \"example-transmission-bpp.com\",\n \"total_quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"energy-resource-solar-001\",\n \"beckn:quantity\": {\n \"unitQuantity\": 15.0,\n \"unitText\": \"kWh\"\n },\n \"beckn:orderItemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyOrderItem\",\n \"providerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyCustomer\",\n \"meterId\": \"der://meter/98765456\",\n \"utilityCustomerId\": \"BESCOM-CUST-001\",\n \"utilityId\": \"BESCOM-KA\"\n }\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-morning-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Morning Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\n \"energy-resource-solar-001\"\n ],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"unitText\": \"kWh\",\n \"applicableQuantity\": {\n \"unitQuantity\": 20.0,\n \"unitText\": \"kWh\"\n }\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-v2/refs/heads/p2p-trading/schema/EnergyTrade/v0.3/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"deliveryWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T06:00:00Z\",\n \"schema:endTime\": \"2026-01-09T12:00:00Z\"\n },\n \"validityWindow\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startTime\": \"2026-01-09T00:00:00Z\",\n \"schema:endTime\": \"2026-01-09T05:00:00Z\"\n }\n }\n }\n }\n ],\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:mode\": \"DELIVERY\"\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-cascaded-p2p-energy-001\",\n \"beckn:amount\": {\n \"currency\": \"USD\",\n \"value\": 2.25\n },\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:paymentStatus\": \"INITIATED\",\n \"beckn:paymentAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/main/schema/PaymentSettlement/v1/context.jsonld\",\n \"@type\": \"PaymentSettlement\",\n \"settlementAccounts\": [\n {\n \"beneficiaryId\": \"p2pTrading-bpp.com\",\n \"accountHolderName\": \"P2P Trading Platform Pvt Ltd\",\n \"accountNumber\": \"5555666677\",\n \"ifscCode\": \"SBIN0001234\",\n \"bankName\": \"State Bank of India\",\n \"vpa\": \"p2p-trading@upi\"\n }\n ]\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{bpp_adapter_url}}/init", + "host": [ + "{{bpp_adapter_url}}" + ], + "path": [ + "init" + ] + }, + "description": "Init request: cascaded-init-request" + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "// Pure JS pre-request script to replace moment()", + "// 1) ISO 8601 timestamp without needing moment", + "const isoTimestamp = new Date().toISOString();", + "pm.collectionVariables.set('iso_date', isoTimestamp);", + "" + ] + } + } + ], + "variable": [ + { + "key": "domain", + "value": "beckn.one:deg:p2p-trading-interdiscom:2.0.0" + }, + { + "key": "version", + "value": "2.0.0" + }, + { + "key": "bap_id", + "value": "p2p-trading-sandbox1.com" + }, + { + "key": "bap_uri", + "value": "http://onix-bap:8081/bap/receiver" + }, + { + "key": "bpp_id", + "value": "p2p-trading-sandbox2.com" + }, + { + "key": "bpp_uri", + "value": "http://onix-bpp:8082/bpp/receiver" + }, + { + "key": "transaction_id", + "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" + }, + { + "key": "iso_date", + "value": "" + }, + { + "key": "bpp_adapter_url", + "value": "http://localhost:8082/bpp/caller" + }, + { + "key": "bap_adapter_url", + "value": "http://localhost:8081/bap/caller" + } + ] +} \ No newline at end of file diff --git a/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:deg_ledger_collection.json b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:deg_ledger_collection.json new file mode 100644 index 00000000..be7b24e3 --- /dev/null +++ b/testnet/p2p-trading-interdiscom-devkit/postman/p2p-trading-interdiscom:deg_ledger_collection.json @@ -0,0 +1,121 @@ +{ + "info": { + "_postman_id": "18b48b79-2246-4b7b-b16c-df9a67af6dfb", + "name": "p2p-trading-interdiscom:DEG Ledger Collection", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "20005936" + }, + "item": [ + { + "name": "Platform Create Trade Record", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"role\": \"SELLER_DISCOM\",\n \"transactionId\": \"txn-2026-01-20-001\",\n \"orderItemId\": \"item-001\",\n \"platformIdBuyer\": \"bap.energy-exchange.in\",\n \"platformIdSeller\": \"bpp.solar-prosumer.in\",\n \"discomIdBuyer\": \"BESCOM-SR\",\n \"discomIdSeller\": \"TPDDL-DL\",\n \"buyerId\": \"CA-BESCOM-1234567\",\n \"sellerId\": \"DEG-TPDDL-87654321\",\n \"tradeTime\": \"2026-01-20T18:30:00.000Z\",\n \"deliveryStartTime\": \"2026-01-20T19:30:00.000Z\",\n \"deliveryEndTime\": \"2026-01-20T20:30:00.000Z\",\n \"tradeDetails\": [\n {\n \"tradeQty\": 5.5,\n \"tradeType\": \"ENERGY\",\n \"tradeUnit\": \"KWH\"\n }\n ],\n \"clientReference\": \"client-ref-001\"\n }", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{deg_ledger_host}}/ledger/put", + "host": [ + "{{deg_ledger_host}}" + ], + "path": [ + "ledger", + "put" + ] + } + }, + "response": [] + }, + { + "name": "Update Trade Record", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"role\": \"BUYER_DISCOM\",\n \"transactionId\": \"txn-2026-01-20-001\",\n \"orderItemId\": \"item-001\",\n \"buyerFulfillmentValidationMetrics\": [\n {\n \"validationMetricType\": \"ACTUAL_PUSHED\",\n \"validationMetricValue\": 4.9\n }\n ],\n \"statusBuyerDiscom\": \"COMPLETED\",\n \"note\": \"Buyer discom validation complete\",\n \"clientReference\": \"client-ref-002\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{deg_ledger_host}}/ledger/record", + "host": [ + "{{deg_ledger_host}}" + ], + "path": [ + "ledger", + "record" + ] + } + }, + "response": [] + }, + { + "name": "Get Record", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"discomIdBuyer\": \"BESCOM-SR\",\n \"transactionId\": \"txn-2026-01-20-001\",\n \"limit\": 25,\n \"offset\": 0,\n \"sort\": \"tradeTime\",\n \"sortOrder\": \"desc\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{deg_ledger_host}}/ledger/get", + "host": [ + "{{deg_ledger_host}}" + ], + "path": [ + "ledger", + "get" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "packages": {}, + "requests": {}, + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "deg_ledger_host", + "value": "https://34.93.166.38.sslip.io" + } + ] +} \ No newline at end of file diff --git a/testnet/postman-collections/v2/EV_Charging/BAP-DEG-EV-Charging-Final.postman_collection.json b/testnet/postman-collections/v2/EV_Charging/BAP-DEG-EV-Charging-Final.postman_collection.json deleted file mode 100644 index 23a04fb5..00000000 --- a/testnet/postman-collections/v2/EV_Charging/BAP-DEG-EV-Charging-Final.postman_collection.json +++ /dev/null @@ -1,533 +0,0 @@ -{ - "info": { - "_postman_id": "a3e400b5-697c-49db-8e9e-239c54d6cc5d", - "name": "BAP-DEG:EV-Charging-Final", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "20005936" - }, - "item": [ - { - "name": "discover", - "item": [ - { - "name": "along-a-route", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n \"message\": {\n \"spatial\": [\n {\n \"op\": \"s_dwithin\",\n \"targets\": \"$['beckn:availableAt'][*]['geo']\",\n \"geometry\": {\n \"type\": \"LineString\",\n \"coordinates\": [\n [\n 77.5946,\n 12.9716\n ],\n [\n 76.6394,\n 12.2958\n ]\n ]\n },\n \"distanceMeters\": 5000\n }\n ]\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - }, - { - "name": "by-EVSE", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n\"message\": {\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?(@.beckn:itemAttributes.evseId == 'IN*PG*IND*01*TYPE2*A')]\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - }, - { - "name": "by-a-CPO", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n \"message\": {\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?(@.beckn:provider.beckn:id == 'ecopower-charging')]\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - }, - { - "name": "by-a-station", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n\"message\": {\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?(@.beckn:id=='ITEM-BTM-DC60')]\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - }, - { - "name": "within-a-boundary", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n \"message\": {\n \"spatial\": [\n {\n \"op\": \"s_dwithin\",\n \"targets\": \"$['beckn:availableAt'][*]['geo']\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": [\n 77.5900,\n 12.9400\n ]\n },\n \"distanceMeters\": 10000\n }\n ]\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - }, - { - "name": "within-a-timerange", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n \"message\": {\n \"spatial\": [\n {\n \"op\": \"s_dwithin\",\n \"targets\": \"$['beckn:availableAt'][*]['geo']\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": [77.59, 12.94]\n }\n }\n ],\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?(@.beckn:itemAttributes.connectorType == 'CCS2' && @.beckn:availabilityWindow.schema:startTime <= '12:30:00' && @.beckn:availabilityWindow.schema:endTime >= '14:30:00')]\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - }, - { - "name": "connector-spec", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n\"message\": {\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?(@.beckn:itemAttributes.connectorType == 'CCS2' && @.beckn:itemAttributes.maxPowerKW >= 50)]\"\n },\n \"spatial\": [\n {\n \"op\": \"s_dwithin\",\n \"targets\": \"$['beckn:availableAt'][*]['geo']\",\n \"geometry\": { \"type\": \"Point\", \"coordinates\": [77.59, 12.94] },\n \"distanceMeters\": 10000\n }\n ]\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - }, - { - "name": "vehicle-spec", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\",\n \"schema_context\": [\n \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingService/v1/context.jsonld\"\n ]\n },\n\"message\": {\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?(@.beckn:fulfillment.beckn:deliveryAttributes.vehicle.make == 'Tata' && @.beckn:fulfillment.beckn:deliveryAttributes.vehicle.model == 'Nexon-EV' )]\"\n },\n \"spatial\": [\n {\n \"op\": \"s_dwithin\",\n \"targets\": \"$['beckn:availableAt'][*]['geo']\",\n \"geometry\": {\n \"type\": \"Point\",\n \"coordinates\": [\n 77.6000,\n 12.9500\n ]\n },\n \"distanceMeters\": 8000\n }\n ]\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "select", - "item": [ - { - "name": "select", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"select\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-ev-charging-001\",\n \"beckn:orderStatus\": \"CREATED\",\n \"beckn:seller\": \"ecopower-charging\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-123\",\n \"beckn:role\": \"BUYER\",\n \"beckn:displayName\": \"Ravi Kumar\",\n \"beckn:taxID\": \"GSTIN29ABCDE1234F1Z5\"\n },\n \"beckn:orderValue\": {\n \"currency\": \"INR\",\n \"value\": 100.0\n },\n \"beckn:orderItems\": [\n {\n \"beckn:lineId\": \"line-001\",\n \"beckn:orderedItem\": \"ev-charger-ccs2-001\",\n \"beckn:quantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 2.5\n },\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-ccs2-60kw-kwh\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Per-kWh Tariff - CCS2 60kW\"\n },\n \"beckn:items\": [\n \"ev-charger-ccs2-001\"\n ],\n \"beckn:provider\": \"ecopower-charging\",\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 18.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 1\n }\n },\n \"beckn:validity\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startDate\": \"2024-10-01T00:00:00Z\",\n \"schema:endDate\": \"2025-01-15T23:59:59Z\"\n },\n \"beckn:acceptedPaymentMethod\": [\n \"UPI\",\n \"CREDIT_CARD\",\n \"WALLET\"\n ],\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld\",\n \"@type\": \"ChargingOffer\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.5\n },\n \"idleFeePolicy\": \"₹2/min after 10 min post-charge\"\n }\n }\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.5\n }\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/select", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "select" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "init", - "item": [ - { - "name": "init", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-123456\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:seller\": \"cpo1.com\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-123\",\n \"beckn:role\": \"BUYER\",\n \"beckn:displayName\": \"Ravi Kumar\",\n \"beckn:taxID\": \"GSTIN29ABCDE1234F1Z5\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:lineId\": \"line-001\",\n \"beckn:orderedItem\": \"pe-charging-01\",\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"name\": \"EV Charging Session Offer\",\n \"short_desc\": \"Fast charging session with CCS2 connector\"\n },\n \"beckn:items\": [\n \"pe-charging-01\"\n ],\n \"beckn:provider\": \"cpo1.com\",\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 18.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 1\n }\n },\n \"beckn:validity\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startDate\": \"2025-01-27T00:00:00Z\",\n \"schema:endDate\": \"2025-04-27T23:59:59Z\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld\",\n \"@type\": \"ChargingOffer\",\n \"offerType\": \"CHARGING_SESSION\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.0\n },\n \"discountPercentage\": 20.0\n }\n },\n \"beckn:quantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n },\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 90.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"INR\",\n \"value\": 128.64,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 100.0,\n \"currency\": \"INR\",\n \"description\": \"Base charging session cost (100 INR)\"\n },\n {\n \"type\": \"SURCHARGE\",\n \"value\": 20.0,\n \"currency\": \"INR\",\n \"description\": \"Surge price (20%)\"\n },\n {\n \"type\": \"DISCOUNT\",\n \"value\": -15.0,\n \"currency\": \"INR\",\n \"description\": \"Offer discount (15%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 10.0,\n \"currency\": \"INR\",\n \"description\": \"Service fee\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 13.64,\n \"currency\": \"INR\",\n \"description\": \"Overcharge estimation\"\n }\n ]\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-123e4567-e89b-12d3-a456-426614174000\",\n \"beckn:amount\": {\n \"currency\": \"INR\",\n \"value\": 128.64\n },\n \"beckn:paymentURL\": \"https://payments.bluechargenet-aggregator.io/pay?transaction_id=$transaction_id&amount=$amount\",\n \"beckn:txnRef\": \"TXN-123456789\",\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:acceptedPaymentMethod\": [\n \"BANK_TRANSFER\",\n \"UPI\",\n \"WALLET\"\n ],\n \"beckn:paymentStatus\": \"INITIATED\"\n },\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-001\",\n \"beckn:mode\": \"RESERVATION\",\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionStatus\": \"PENDING\",\n \"connectorType\": \"CCS2\",\n \"maxPowerKW\": 50,\n \"vehicleMake\": \"Tata\",\n \"vehicleModel\": \"Nexon EV\"\n }\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionPreferences\": {\n \"preferredStartTime\": \"2025-01-27T10:00:00Z\",\n \"preferredEndTime\": \"2025-01-27T11:30:00Z\",\n \"notificationPreferences\": {\n \"email\": true,\n \"sms\": true,\n \"push\": false\n }\n }\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/init", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "init" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "confirm", - "item": [ - { - "name": "confirm", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-123456\",\n \"beckn:orderStatus\": \"PENDING\",\n \"beckn:orderNumber\": \"ORD-2025-001\",\n \"beckn:seller\": \"cpo1.com\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-123\",\n \"beckn:role\": \"BUYER\",\n \"beckn:displayName\": \"Ravi Kumar\",\n \"beckn:taxID\": \"GSTIN29ABCDE1234F1Z5\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:lineId\": \"line-001\",\n \"beckn:orderedItem\": \"pe-charging-01\",\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"name\": \"EV Charging Session Offer\",\n \"short_desc\": \"Fast charging session with CCS2 connector\"\n },\n \"beckn:items\": [\n \"pe-charging-01\"\n ],\n \"beckn:provider\": \"cpo1.com\",\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 18.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 1\n }\n },\n \"beckn:validity\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startDate\": \"2025-01-27T00:00:00Z\",\n \"schema:endDate\": \"2025-04-27T23:59:59Z\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld\",\n \"@type\": \"ChargingOffer\",\n \"offerType\": \"CHARGING_SESSION\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.0\n },\n \"discountPercentage\": 20.0\n }\n },\n \"beckn:quantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n },\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 90.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"INR\",\n \"value\": 128.64,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 100.0,\n \"currency\": \"INR\",\n \"description\": \"Base charging session cost (100 INR)\"\n },\n {\n \"type\": \"SURCHARGE\",\n \"value\": 20.0,\n \"currency\": \"INR\",\n \"description\": \"Surge price (20%)\"\n },\n {\n \"type\": \"DISCOUNT\",\n \"value\": -15.0,\n \"currency\": \"INR\",\n \"description\": \"Offer discount (15%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 10.0,\n \"currency\": \"INR\",\n \"description\": \"Service fee\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 13.64,\n \"currency\": \"INR\",\n \"description\": \"Overcharge estimation\"\n }\n ]\n },\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-001\",\n \"beckn:mode\": \"RESERVATION\",\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"connectorType\": \"CCS2\",\n \"maxPowerKW\": 50,\n \"vehicleMake\": \"Tata\",\n \"vehicleModel\": \"Nexon EV\",\n \"sessionStatus\": \"PENDING\"\n }\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-123e4567-e89b-12d3-a456-426614174000\",\n \"beckn:amount\": {\n \"currency\": \"INR\",\n \"value\": 128.64\n },\n \"beckn:paymentURL\": \"https://payments.bluechargenet-aggregator.io/pay?transaction_id=$transaction_id&amount=$amount\",\n \"beckn:txnRef\": \"TXN-123456789\",\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:acceptedPaymentMethod\": [\n \"BANK_TRANSFER\",\n \"UPI\",\n \"WALLET\"\n ],\n \"beckn:paymentStatus\": \"COMPLETED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionPreferences\": {\n \"preferredStartTime\": \"2025-01-27T10:00:00Z\",\n \"preferredEndTime\": \"2025-01-27T11:30:00Z\",\n \"notificationPreferences\": {\n \"email\": true,\n \"sms\": true,\n \"push\": false\n }\n },\n \"authorizationMode\": \"OTP\",\n \"authorizationOtpHint\": \"OTP will be shared to the user's registered number to confirm order\",\n \"sessionStatus\": \"PENDING\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/confirm", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "confirm" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "update", - "item": [ - { - "name": "update", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"update\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-bpp-789012\",\n \"beckn:orderStatus\": \"INPROGRESS\",\n \"beckn:orderNumber\": \"ORD-2025-001\",\n \"beckn:seller\": \"cpo1.com\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-123\",\n \"beckn:role\": \"BUYER\",\n \"beckn:displayName\": \"Ravi Kumar\",\n \"beckn:taxID\": \"GSTIN29ABCDE1234F1Z5\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:lineId\": \"line-001\",\n \"beckn:orderedItem\": \"pe-charging-01\",\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"name\": \"EV Charging Session Offer\",\n \"short_desc\": \"Fast charging session with CCS2 connector\"\n },\n \"beckn:items\": [\n \"pe-charging-01\"\n ],\n \"beckn:provider\": \"cpo1.com\",\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 18.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 1\n }\n },\n \"beckn:validity\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startDate\": \"2025-01-27T00:00:00Z\",\n \"schema:endDate\": \"2025-04-27T23:59:59Z\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld\",\n \"@type\": \"ChargingOffer\",\n \"offerType\": \"CHARGING_SESSION\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.0\n },\n \"discountPercentage\": 20.0\n }\n },\n \"beckn:quantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n },\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 90.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"INR\",\n \"value\": 128.64,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 100.0,\n \"currency\": \"INR\",\n \"description\": \"Base charging session cost (100 INR)\"\n },\n {\n \"type\": \"SURCHARGE\",\n \"value\": 20.0,\n \"currency\": \"INR\",\n \"description\": \"Surge price (20%)\"\n },\n {\n \"type\": \"DISCOUNT\",\n \"value\": -15.0,\n \"currency\": \"INR\",\n \"description\": \"Offer discount (15%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 10.0,\n \"currency\": \"INR\",\n \"description\": \"Service fee\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 13.64,\n \"currency\": \"INR\",\n \"description\": \"Overcharge estimation\"\n }\n ]\n },\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-001\",\n \"beckn:mode\": \"RESERVATION\",\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionStatus\": \"PENDING\",\n \"connectorType\": \"CCS2\",\n \"maxPowerKW\": 50,\n \"authorizationMode\": \"OTP\",\n \"vehicleMake\": \"Tata\",\n \"vehicleModel\": \"Nexon EV\"\n }\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-123e4567-e89b-12d3-a456-426614174000\",\n \"beckn:amount\": {\n \"currency\": \"INR\",\n \"value\": 128.64\n },\n \"beckn:paymentURL\": \"https://payments.bluechargenet-aggregator.io/pay?transaction_id=$transaction_id&amount=$amount\",\n \"beckn:txnRef\": \"TXN-123456789\",\n \"beckn:paidAt\": \"2025-01-27T10:05:00Z\",\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:acceptedPaymentMethod\": [\n \"BANK_TRANSFER\",\n \"UPI\",\n \"WALLET\"\n ],\n \"beckn:paymentStatus\": \"COMPLETED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionPreferences\": {\n \"preferredStartTime\": \"2025-01-27T10:00:00Z\",\n \"preferredEndTime\": \"2025-01-27T11:30:00Z\",\n \"notificationPreferences\": {\n \"email\": true,\n \"sms\": true,\n \"push\": false\n }\n },\n \"authorizationMode\": \"OTP\",\n \"authorizationOtpHint\": \"OTP will be shared to the user's registered number to confirm order\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/update", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "update" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "track", - "item": [ - { - "name": "track", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"track\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"beckn:id\": \"order-bpp-789012\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/track", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "track" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "rating", - "item": [ - { - "name": "rating", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"rating\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"id\": \"fulfillment-001\",\n \"ratingValue\": 5,\n \"bestRating\": 5,\n \"worstRating\": 1,\n \"category\": \"fulfillment\",\n \"feedback\": {\n \"comments\": \"Excellent charging experience! The station was clean, easy to find, and the charging was fast and reliable. The staff was helpful and the payment process was smooth.\",\n \"tags\": [\"fast-charging\", \"easy-to-use\", \"clean-station\", \"helpful-staff\", \"smooth-payment\"]\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/rating", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "rating" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "support", - "item": [ - { - "name": "support", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"support\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"ref_id\": \"order-bpp-789012\",\n \"ref_type\": \"order\"\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/support", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "support" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "cancel", - "item": [ - { - "name": "cancel", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"cancel\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"beckn:id\": \"b989c9a9-f603-4d44-b38d-26fd72286b38\",\n \"beckn:orderItems\": [\n {\n \"beckn:orderedItem\": \"pe-charging-01\"\n }\n ]\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/cancel", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "cancel" - ] - } - }, - "response": [] - } - ] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - "" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "domain", - "value": "beckn.one:deg:ev-charging:2.0.0" - }, - { - "key": "version", - "value": "2.0.0" - }, - { - "key": "bap_id", - "value": "ev-charging.sandbox1.com" - }, - { - "key": "bap_uri", - "value": "http://onix-bap:8081/bap/receiver" - }, - { - "key": "bpp_id", - "value": "ev-charging.sandbox2.com" - }, - { - "key": "bpp_uri", - "value": "http://onix-bpp:8082/bpp/receiver" - }, - { - "key": "bap_adapter_url", - "value": "http://localhost:8081/bap/caller" - }, - { - "key": "transaction_id", - "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" - }, - { - "key": "bpp_adapter_url", - "value": "http://localhost:8082/bpp/caller" - } - ] -} \ No newline at end of file diff --git a/testnet/postman-collections/v2/EV_Charging/BPP-DEG-EV-Charging-Final.postman_collection.json b/testnet/postman-collections/v2/EV_Charging/BPP-DEG-EV-Charging-Final.postman_collection.json deleted file mode 100644 index e7eb712a..00000000 --- a/testnet/postman-collections/v2/EV_Charging/BPP-DEG-EV-Charging-Final.postman_collection.json +++ /dev/null @@ -1,173 +0,0 @@ -{ - "info": { - "_postman_id": "ba33acbf-cfd7-40b4-b9a4-b55c572ad6e2", - "name": "BPP-DEG:EV-Charging-Final", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "20005936" - }, - "item": [ - { - "name": "on_status", - "item": [ - { - "name": "on_status-charging-error", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"select\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-bpp-789012\",\n \"beckn:orderStatus\": \"INPROGRESS\",\n \"beckn:orderNumber\": \"ORD-2025-001\",\n \"beckn:seller\": \"cpo1.com\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-123\",\n \"beckn:role\": \"BUYER\",\n \"beckn:displayName\": \"Ravi Kumar\",\n \"beckn:taxID\": \"GSTIN29ABCDE1234F1Z5\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:lineId\": \"line-001\",\n \"beckn:orderedItem\": \"pe-charging-01\",\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"name\": \"EV Charging Session Offer\",\n \"short_desc\": \"Fast charging session with CCS2 connector\"\n },\n \"beckn:items\": [\n \"pe-charging-01\"\n ],\n \"beckn:provider\": \"cpo1.com\",\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 18.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 1\n }\n },\n \"beckn:validity\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startDate\": \"2025-01-27T00:00:00Z\",\n \"schema:endDate\": \"2025-04-27T23:59:59Z\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld\",\n \"@type\": \"ChargingOffer\",\n \"offerType\": \"CHARGING_SESSION\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.0\n },\n \"discountPercentage\": 20.0\n }\n },\n \"beckn:quantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n },\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 90.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"INR\",\n \"value\": 128.64,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 100.0,\n \"currency\": \"INR\",\n \"description\": \"Base charging session cost (100 INR)\"\n },\n {\n \"type\": \"SURCHARGE\",\n \"value\": 20.0,\n \"currency\": \"INR\",\n \"description\": \"Surge price (20%)\"\n },\n {\n \"type\": \"DISCOUNT\",\n \"value\": -15.0,\n \"currency\": \"INR\",\n \"description\": \"Offer discount (15%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 10.0,\n \"currency\": \"INR\",\n \"description\": \"Service fee\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 13.64,\n \"currency\": \"INR\",\n \"description\": \"Overcharge estimation\"\n }\n ]\n },\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-001\",\n \"beckn:mode\": \"RESERVATION\",\n \"trackingAction\": {\n \"@type\": \"schema:TrackAction\",\n \"target\": {\n \"@type\": \"schema:EntryPoint\",\n \"url\": \"https://track.bluechargenet-aggregator.io/session/SESSION-9876543210\"\n },\n \"deliveryMethod\": \"RESERVATION\",\n \"reservationId\": \"TRACK-SESSION-9876543210\"\n },\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionStatus\": \"INTERRUPTED\",\n \"connectorType\": \"CCS2\",\n \"maxPowerKW\": 50,\n \"authorizationMode\": \"OTP\",\n \"vehicleMake\": \"Tata\",\n \"vehicleModel\": \"Nexon EV\"\n }\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-123e4567-e89b-12d3-a456-426614174000\",\n \"beckn:amount\": {\n \"currency\": \"INR\",\n \"value\": 128.64\n },\n \"beckn:paymentURL\": \"https://payments.bluechargenet-aggregator.io/pay?transaction_id=$transaction_id&amount=$amount\",\n \"beckn:txnRef\": \"TXN-123456789\",\n \"beckn:paidAt\": \"2025-01-27T10:05:00Z\",\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:acceptedPaymentMethod\": [\n \"BANK_TRANSFER\",\n \"UPI\",\n \"WALLET\"\n ],\n \"beckn:paymentStatus\": \"COMPLETED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionPreferences\": {\n \"preferredStartTime\": \"2025-01-27T10:00:00Z\",\n \"preferredEndTime\": \"2025-01-27T11:30:00Z\",\n \"notificationPreferences\": {\n \"email\": true,\n \"sms\": true,\n \"push\": false\n }\n },\n \"authorizationMode\": \"OTP\",\n \"authorizationOtpHint\": \"OTP will be shared to the user's registered number to confirm order\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_status", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_status" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "on_update", - "item": [ - { - "name": "on_update-end-charging", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"select\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-bpp-789012\",\n \"beckn:orderStatus\": \"COMPLETED\",\n \"beckn:orderNumber\": \"ORD-2025-001\",\n \"beckn:seller\": \"cpo1.com\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-123\",\n \"beckn:role\": \"BUYER\",\n \"beckn:displayName\": \"Ravi Kumar\",\n \"beckn:taxID\": \"GSTIN29ABCDE1234F1Z5\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:lineId\": \"line-001\",\n \"beckn:orderedItem\": \"pe-charging-01\",\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"name\": \"EV Charging Session Offer\",\n \"short_desc\": \"Fast charging session with CCS2 connector\"\n },\n \"beckn:items\": [\n \"pe-charging-01\"\n ],\n \"beckn:provider\": \"cpo1.com\",\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 18.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 1\n }\n },\n \"beckn:validity\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startDate\": \"2025-01-27T00:00:00Z\",\n \"schema:endDate\": \"2025-04-27T23:59:59Z\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld\",\n \"@type\": \"ChargingOffer\",\n \"offerType\": \"CHARGING_SESSION\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.0\n },\n \"discountPercentage\": 20.0\n }\n },\n \"beckn:quantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n },\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 90.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"INR\",\n \"value\": 128.64,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 100.0,\n \"currency\": \"INR\",\n \"description\": \"Base charging session cost (100 INR)\"\n },\n {\n \"type\": \"SURCHARGE\",\n \"value\": 20.0,\n \"currency\": \"INR\",\n \"description\": \"Surge price (20%)\"\n },\n {\n \"type\": \"DISCOUNT\",\n \"value\": -15.0,\n \"currency\": \"INR\",\n \"description\": \"Offer discount (15%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 10.0,\n \"currency\": \"INR\",\n \"description\": \"Service fee\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 13.64,\n \"currency\": \"INR\",\n \"description\": \"Overcharge estimation\"\n }\n ]\n },\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-001\",\n \"beckn:mode\": \"RESERVATION\",\n \"trackingAction\": {\n \"@type\": \"schema:TrackAction\",\n \"target\": {\n \"@type\": \"schema:EntryPoint\",\n \"url\": \"https://track.bluechargenet-aggregator.io/session/SESSION-9876543210\"\n },\n \"deliveryMethod\": \"RESERVATION\",\n \"reservationId\": \"TRACK-SESSION-9876543210\"\n },\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionStatus\": \"COMPLETED\",\n \"connectorType\": \"CCS2\",\n \"maxPowerKW\": 50,\n \"authorizationMode\": \"OTP\",\n \"vehicleMake\": \"Tata\",\n \"vehicleModel\": \"Nexon EV\"\n }\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-123e4567-e89b-12d3-a456-426614174000\",\n \"beckn:amount\": {\n \"currency\": \"INR\",\n \"value\": 128.64\n },\n \"beckn:paymentURL\": \"https://payments.bluechargenet-aggregator.io/pay?transaction_id=$transaction_id&amount=$amount\",\n \"beckn:txnRef\": \"TXN-123456789\",\n \"beckn:paidAt\": \"2025-01-27T10:05:00Z\",\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:acceptedPaymentMethod\": [\n \"BANK_TRANSFER\",\n \"UPI\",\n \"WALLET\"\n ],\n \"beckn:paymentStatus\": \"COMPLETED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionPreferences\": {\n \"preferredStartTime\": \"2025-01-27T10:00:00Z\",\n \"preferredEndTime\": \"2025-01-27T11:30:00Z\",\n \"notificationPreferences\": {\n \"email\": true,\n \"sms\": true,\n \"push\": false\n }\n },\n \"authorizationMode\": \"OTP\",\n \"authorizationOtpHint\": \"OTP will be shared to the user's registered number to confirm order\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_update", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_update" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "on_cancel", - "item": [ - { - "name": "on_cancel-reserved-slot", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"select\",\n \"domain\": \"{{domain}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"message_id\": \"{{$guid}}\",\n \"timestamp\": \"{{$timestamp}}\",\n \"ttl\": \"PT30S\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-bpp-789012\",\n \"beckn:orderStatus\": \"CANCELLED\",\n \"beckn:orderNumber\": \"ORD-2025-001\",\n \"beckn:seller\": \"cpo1.com\",\n \"beckn:buyer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Buyer\",\n \"beckn:id\": \"user-123\",\n \"beckn:role\": \"BUYER\",\n \"beckn:displayName\": \"Ravi Kumar\",\n \"beckn:taxID\": \"GSTIN29ABCDE1234F1Z5\"\n },\n \"beckn:orderItems\": [\n {\n \"beckn:lineId\": \"line-001\",\n \"beckn:orderedItem\": \"pe-charging-01\",\n \"beckn:acceptedOffer\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"name\": \"EV Charging Session Offer\",\n \"short_desc\": \"Fast charging session with CCS2 connector\"\n },\n \"beckn:items\": [\n \"pe-charging-01\"\n ],\n \"beckn:provider\": \"cpo1.com\",\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 18.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 1\n }\n },\n \"beckn:validity\": {\n \"@type\": \"beckn:TimePeriod\",\n \"schema:startDate\": \"2025-01-27T00:00:00Z\",\n \"schema:endDate\": \"2025-04-27T23:59:59Z\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingOffer/v1/context.jsonld\",\n \"@type\": \"ChargingOffer\",\n \"offerType\": \"CHARGING_SESSION\",\n \"buyerFinderFee\": {\n \"feeType\": \"PERCENTAGE\",\n \"feeValue\": 2.0\n },\n \"discountPercentage\": 20.0\n }\n },\n \"beckn:quantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n },\n \"beckn:price\": {\n \"currency\": \"INR\",\n \"value\": 90.0,\n \"applicableQuantity\": {\n \"unitText\": \"Kilowatt Hour\",\n \"unitCode\": \"KWH\",\n \"unitQuantity\": 5\n }\n }\n }\n ],\n \"beckn:orderValue\": {\n \"currency\": \"INR\",\n \"value\": 128.64,\n \"components\": [\n {\n \"type\": \"UNIT\",\n \"value\": 100.0,\n \"currency\": \"INR\",\n \"description\": \"Base charging session cost (100 INR)\"\n },\n {\n \"type\": \"SURCHARGE\",\n \"value\": 20.0,\n \"currency\": \"INR\",\n \"description\": \"Surge price (20%)\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 10.0,\n \"currency\": \"INR\",\n \"description\": \"Service fee\"\n },\n {\n \"type\": \"FEE\",\n \"value\": 13.64,\n \"currency\": \"INR\",\n \"description\": \"Overcharge estimation\"\n },\n {\n \"type\": \"DISCOUNT\",\n \"value\": -15.0,\n \"currency\": \"INR\",\n \"description\": \"Offer discount (15%)\"\n }\n ]\n },\n \"beckn:fulfillment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-001\",\n \"beckn:mode\": \"RESERVATION\",\n \"beckn:deliveryAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"connectorType\": \"CCS2\",\n \"maxPowerKW\": 50,\n \"vehicleMake\": \"Tata\",\n \"vehicleModel\": \"Nexon EV\"\n }\n },\n \"beckn:payment\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-123e4567-e89b-12d3-a456-426614174000\",\n \"beckn:amount\": {\n \"currency\": \"INR\",\n \"value\": 128.64\n },\n \"beckn:paymentURL\": \"https://payments.bluechargenet-aggregator.io/pay?transaction_id=$transaction_id&amount=$amount\",\n \"beckn:txnRef\": \"TXN-123456789\",\n \"beckn:paidAt\": \"2025-01-27T10:05:00Z\",\n \"beckn:beneficiary\": \"BPP\",\n \"beckn:acceptedPaymentMethod\": [\n \"BANK_TRANSFER\",\n \"UPI\",\n \"WALLET\"\n ],\n \"beckn:paymentStatus\": \"COMPLETED\"\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EvChargingSession/v1/context.jsonld\",\n \"@type\": \"ChargingSession\",\n \"sessionPreferences\": {\n \"preferredStartTime\": \"2025-01-27T10:00:00Z\",\n \"preferredEndTime\": \"2025-01-27T11:30:00Z\",\n \"notificationPreferences\": {\n \"email\": true,\n \"sms\": true,\n \"push\": false\n }\n },\n \"authorizationMode\": \"OTP\",\n \"authorizationOtpHint\": \"OTP will be shared to the user's registered number to confirm order\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_cancel", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_cancel" - ] - } - }, - "response": [] - } - ] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - "// Pure JS pre-request script to replace moment()", - "", - "// 1) ISO 8601 timestamp without needing moment", - "const isoTimestamp = new Date().toISOString();", - "pm.collectionVariables.set('iso_date', isoTimestamp);" - ] - } - }, - { - "listen": "test", - "script": { - "type": "text/javascript", - "packages": {}, - "requests": {}, - "exec": [ - "" - ] - } - } - ], - "variable": [ - { - "key": "domain", - "value": "beckn.one:deg:ev-charging:2.0.0" - }, - { - "key": "version", - "value": "2.0.0" - }, - { - "key": "bap_id", - "value": "ev-charging.sandbox1.com" - }, - { - "key": "bap_uri", - "value": "http://onix-bap:8081/bap/receiver" - }, - { - "key": "bpp_id", - "value": "ev-charging.sandbox2.com" - }, - { - "key": "bpp_uri", - "value": "http://onix-bpp:8082/bpp/receiver" - }, - { - "key": "bap_adapter_url", - "value": "http://localhost:8081/bap/caller" - }, - { - "key": "transaction_id", - "value": "2b4d69aa-22e4-4c78-9f56-5a7b9e2b2002" - }, - { - "key": "bpp_adapter_url", - "value": "http://localhost:3002/api/webhook/trigger" - }, - { - "key": "iso_date", - "value": "" - } - ] -} \ No newline at end of file diff --git a/testnet/postman-collections/v2/P2P_Trading/BAP-DEG-P2P-Trading.postman_collection.json b/testnet/postman-collections/v2/P2P_Trading/BAP-DEG-P2P-Trading.postman_collection.json deleted file mode 100644 index 437bbf44..00000000 --- a/testnet/postman-collections/v2/P2P_Trading/BAP-DEG-P2P-Trading.postman_collection.json +++ /dev/null @@ -1,275 +0,0 @@ -{ - "info": { - "_postman_id": "bap-deg-p2p-trading-collection", - "name": "BAP-DEG:P2P-Trading", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "description": "Postman collection for BAP (Buyer Application Platform) implementing P2P Energy Trading APIs based on Beckn Protocol v2" - }, - "item": [ - { - "name": "discover", - "item": [ - { - "name": "discover-solar-grid-injection", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"discover\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\",\n \"location\": {\n \"city\": {\n \"code\": \"BLR\",\n \"name\": \"Bangalore\"\n },\n \"country\": {\n \"code\": \"IND\",\n \"name\": \"India\"\n }\n }\n },\n \"message\": {\n \"text_search\": \"solar energy grid injection\",\n \"filters\": {\n \"type\": \"jsonpath\",\n \"expression\": \"$[?(@.itemAttributes.sourceType == 'SOLAR' && @.itemAttributes.deliveryMode == 'GRID_INJECTION' && @.itemAttributes.availableQuantity >= 10.0 && @.itemAttributes.productionWindow.start <= '2024-10-04T10:00:00Z' && @.itemAttributes.productionWindow.end >= '2024-10-04T18:00:00Z')]\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/discover", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "discover" - ] - }, - "description": "Discover available solar energy resources with grid injection delivery mode. Uses JSONPath filters to find resources matching specific criteria." - }, - "response": [] - } - ] - }, - { - "name": "select", - "item": [ - { - "name": "select-energy-offer", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"select\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/select", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "select" - ] - }, - "description": "Select energy resource and offer to receive a priced quote with breakdown." - }, - "response": [] - } - ] - }, - { - "name": "init", - "item": [ - { - "name": "init-energy-order", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\",\n \"beckn:stops\": [\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-start-001\",\n \"beckn:type\": \"START\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"100200300\"\n },\n \"beckn:time\": {\n \"@type\": \"beckn:Time\",\n \"beckn:range\": {\n \"start\": \"2024-10-04T10:00:00Z\",\n \"end\": \"2024-10-04T18:00:00Z\"\n }\n }\n },\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-end-001\",\n \"beckn:type\": \"END\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"98765456\"\n },\n \"beckn:time\": {\n \"@type\": \"beckn:Time\",\n \"beckn:range\": {\n \"start\": \"2024-10-04T10:00:00Z\",\n \"end\": \"2024-10-04T18:00:00Z\"\n }\n }\n }\n ]\n }\n ],\n \"beckn:payments\": [\n {\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-energy-001\",\n \"beckn:type\": \"ON-FULFILLMENT\",\n \"beckn:status\": \"NOT-PAID\",\n \"beckn:collected_by\": \"BPP\"\n }\n ],\n \"beckn:billing\": {\n \"@type\": \"beckn:Billing\",\n \"beckn:name\": \"Energy Consumer\",\n \"beckn:email\": \"consumer@example.com\",\n \"beckn:phone\": \"+1-555-0100\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/init", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "init" - ] - }, - "description": "Initialize order with fulfillment details (meter IDs, time window) and payment information." - }, - "response": [] - } - ] - }, - { - "name": "confirm", - "item": [ - { - "name": "confirm-energy-order", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\"\n }\n ],\n \"beckn:payments\": [\n {\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-energy-001\",\n \"beckn:type\": \"ON-FULFILLMENT\",\n \"beckn:status\": \"NOT-PAID\",\n \"beckn:collected_by\": \"BPP\"\n }\n ]\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/confirm", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "confirm" - ] - }, - "description": "Confirm order to activate the energy trade contract." - }, - "response": [] - } - ] - }, - { - "name": "status", - "item": [ - { - "name": "status-energy-order", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\"\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/status", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "status" - ] - }, - "description": "Query order and delivery status. Can be called multiple times during delivery to monitor progress." - }, - "response": [] - } - ] - }, - { - "name": "cascaded-init", - "item": [ - { - "name": "cascaded-init-utility", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{cascaded_transaction_id}}\",\n \"bap_id\": \"{{cascaded_bap_id}}\",\n \"bap_uri\": \"{{cascaded_bap_uri}}\",\n \"bpp_id\": \"{{cascaded_bpp_id}}\",\n \"bpp_uri\": \"{{cascaded_bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\",\n \"location\": {\n \"city\": {\n \"code\": \"std:522\",\n \"name\": \"Lucknow\"\n },\n \"country\": {\n \"code\": \"IND\",\n \"name\": \"India\"\n }\n }\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-cascaded-utility-001\",\n \"beckn:provider\": {\n \"@type\": \"beckn:Provider\",\n \"beckn:id\": \"provider-uppcl-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"UPPCL\"\n }\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-utility-registration-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\",\n \"beckn:customer\": {\n \"@type\": \"beckn:Customer\",\n \"beckn:person\": {\n \"@type\": \"schema:Person\",\n \"schema:name\": \"Raj\"\n },\n \"beckn:contact\": {\n \"@type\": \"schema:ContactPoint\",\n \"schema:telephone\": \"+91-1276522222\"\n }\n },\n \"beckn:stops\": [\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-source-utility-001\",\n \"beckn:type\": \"START\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"92982739\"\n },\n \"beckn:time\": {\n \"@type\": \"beckn:Time\",\n \"beckn:range\": {\n \"start\": \"2024-10-04T10:00:00Z\",\n \"end\": \"2024-10-04T18:00:00Z\"\n }\n }\n },\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-target-utility-001\",\n \"beckn:type\": \"END\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"98765456\"\n },\n \"beckn:time\": {\n \"@type\": \"beckn:Time\",\n \"beckn:range\": {\n \"start\": \"2024-10-04T10:00:00Z\",\n \"end\": \"2024-10-04T18:00:00Z\"\n }\n }\n }\n ]\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeContract\",\n \"contractStatus\": \"PENDING\",\n \"sourceMeterId\": \"92982739\",\n \"targetMeterId\": \"98765456\",\n \"contractedQuantity\": 10.0,\n \"tradeStartTime\": \"2024-10-04T10:00:00Z\",\n \"tradeEndTime\": \"2024-10-04T18:00:00Z\",\n \"sourceType\": \"SOLAR\"\n },\n \"beckn:billing\": {\n \"@type\": \"beckn:Billing\",\n \"beckn:name\": \"p2p-Trading-BPP\",\n \"beckn:email\": \"p2tbpp@example.com\",\n \"beckn:phone\": \"+91-1276522222\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bap_adapter_url}}/init", - "host": [ - "{{bap_adapter_url}}" - ], - "path": [ - "init" - ] - }, - "description": "Cascaded init request from P2P Trading BPP to Utility Company (Transmission BPP) to register trade and calculate wheeling charges." - }, - "response": [] - } - ] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "// Pure JS pre-request script to replace moment()", - "", - "// 1) ISO 8601 timestamp without needing moment", - "const isoTimestamp = new Date().toISOString();", - "pm.collectionVariables.set('iso_date', isoTimestamp);" - ] - } - } - ], - "variable": [ - { - "key": "domain", - "value": "energy-trade" - }, - { - "key": "version", - "value": "2.0.0" - }, - { - "key": "bap_id", - "value": "bap.energy-consumer.com" - }, - { - "key": "bap_uri", - "value": "https://bap.energy-consumer.com" - }, - { - "key": "bpp_id", - "value": "bpp.energy-provider.com" - }, - { - "key": "bpp_uri", - "value": "https://bpp.energy-provider.com" - }, - { - "key": "bap_adapter_url", - "value": "http://localhost:8081/bap/caller" - }, - { - "key": "transaction_id", - "value": "txn-energy-001" - }, - { - "key": "cascaded_transaction_id", - "value": "txn-cascaded-energy-001" - }, - { - "key": "cascaded_bap_id", - "value": "p2pTrading-bpp.com" - }, - { - "key": "cascaded_bap_uri", - "value": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2" - }, - { - "key": "cascaded_bpp_id", - "value": "example-transmission-bpp.com" - }, - { - "key": "cascaded_bpp_uri", - "value": "https://api.example-transmission-bpp.com/pilot/bpp/" - }, - { - "key": "iso_date", - "value": "" - } - ] -} diff --git a/testnet/postman-collections/v2/P2P_Trading/BPP-DEG-P2P-Trading.postman_collection.json b/testnet/postman-collections/v2/P2P_Trading/BPP-DEG-P2P-Trading.postman_collection.json deleted file mode 100644 index b90ded7f..00000000 --- a/testnet/postman-collections/v2/P2P_Trading/BPP-DEG-P2P-Trading.postman_collection.json +++ /dev/null @@ -1,302 +0,0 @@ -{ - "info": { - "_postman_id": "bpp-deg-p2p-trading-collection", - "name": "BPP-DEG:P2P-Trading", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "description": "Postman collection for BPP (Buyer Provider Platform) implementing P2P Energy Trading APIs based on Beckn Protocol v2" - }, - "item": [ - { - "name": "on_discover", - "item": [ - { - "name": "on_discover-solar-catalog", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_discover\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"catalogs\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Catalog\",\n \"beckn:id\": \"catalog-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy Trading Catalog\"\n },\n \"beckn:items\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Item\",\n \"beckn:id\": \"energy-resource-solar-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Solar Energy - 30.5 kWh\",\n \"beckn:shortDesc\": \"Carbon Offset Certified Solar Energy\",\n \"beckn:longDesc\": \"High-quality solar energy from verified source with carbon offset certification\"\n },\n \"beckn:provider\": {\n \"@type\": \"beckn:Provider\",\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:itemAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyResource/v0.2/context.jsonld\",\n \"@type\": \"EnergyResource\",\n \"sourceType\": \"SOLAR\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"certificationStatus\": \"Carbon Offset Certified\",\n \"meterId\": \"100200300\",\n \"inverterId\": \"inv-12345\",\n \"availableQuantity\": 30.5,\n \"productionWindow\": {\n \"start\": \"2024-10-04T10:00:00Z\",\n \"end\": \"2024-10-04T18:00:00Z\"\n },\n \"sourceVerification\": {\n \"verified\": true,\n \"verificationDate\": \"2024-09-01T00:00:00Z\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert.pdf\"\n ]\n },\n \"productionAsynchronous\": true\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Offer\",\n \"beckn:id\": \"offer-energy-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"Daily Settlement Solar Energy Offer\"\n },\n \"beckn:provider\": \"provider-solar-farm-001\",\n \"beckn:items\": [\"energy-resource-solar-001\"],\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 0.15,\n \"schema:priceCurrency\": \"USD\",\n \"schema:unitText\": \"kWh\"\n },\n \"beckn:offerAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeOffer/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeOffer\",\n \"pricingModel\": \"PER_KWH\",\n \"settlementType\": \"DAILY\",\n \"wheelingCharges\": {\n \"amount\": 2.5,\n \"currency\": \"USD\",\n \"description\": \"PG&E Grid Services wheeling charge\"\n },\n \"minimumQuantity\": 1.0,\n \"maximumQuantity\": 100.0,\n \"validityWindow\": {\n \"start\": \"2024-10-04T00:00:00Z\",\n \"end\": \"2024-10-04T23:59:59Z\"\n }\n }\n }\n ]\n }\n ]\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_discover", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_discover" - ] - }, - "description": "Response to discover request with catalog containing energy resources and offers." - }, - "response": [] - } - ] - }, - { - "name": "on_select", - "item": [ - { - "name": "on_select-energy-quote", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_select\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:quote\": {\n \"@type\": \"beckn:Quotation\",\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 1.5,\n \"schema:priceCurrency\": \"USD\",\n \"schema:unitText\": \"kWh\"\n },\n \"beckn:breakup\": [\n {\n \"@type\": \"beckn:Breakup\",\n \"beckn:title\": \"Energy Cost (10 kWh @ $0.15/kWh)\",\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 1.5,\n \"schema:priceCurrency\": \"USD\"\n }\n },\n {\n \"@type\": \"beckn:Breakup\",\n \"beckn:title\": \"Wheeling Charges\",\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 2.5,\n \"schema:priceCurrency\": \"USD\"\n }\n }\n ]\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_select", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_select" - ] - }, - "description": "Response to select request with priced quote including energy cost and wheeling charges breakdown." - }, - "response": [] - } - ] - }, - { - "name": "on_init", - "item": [ - { - "name": "on_init-energy-order", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\",\n \"beckn:stops\": [\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-start-001\",\n \"beckn:type\": \"START\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"100200300\"\n }\n },\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-end-001\",\n \"beckn:type\": \"END\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"98765456\"\n }\n }\n ]\n }\n ],\n \"beckn:payments\": [\n {\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-energy-001\",\n \"beckn:type\": \"ON-FULFILLMENT\",\n \"beckn:status\": \"NOT-PAID\",\n \"beckn:collected_by\": \"BPP\"\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeContract\",\n \"contractStatus\": \"PENDING\",\n \"sourceMeterId\": \"100200300\",\n \"targetMeterId\": \"98765456\",\n \"inverterId\": \"inv-12345\",\n \"contractedQuantity\": 10.0,\n \"tradeStartTime\": \"2024-10-04T10:00:00Z\",\n \"tradeEndTime\": \"2024-10-04T18:00:00Z\",\n \"sourceType\": \"SOLAR\",\n \"certification\": {\n \"status\": \"Carbon Offset Certified\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert.pdf\"\n ]\n }\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_init", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_init" - ] - }, - "description": "Response to init request with initialized order and EnergyTradeContract with PENDING status." - }, - "response": [] - } - ] - }, - { - "name": "on_confirm", - "item": [ - { - "name": "on_confirm-energy-order", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_confirm\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\",\n \"beckn:state\": {\n \"@type\": \"beckn:State\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"PENDING\"\n }\n }\n }\n ],\n \"beckn:payments\": [\n {\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-energy-001\",\n \"beckn:type\": \"ON-FULFILLMENT\",\n \"beckn:status\": \"NOT-PAID\",\n \"beckn:collected_by\": \"BPP\"\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeContract\",\n \"contractStatus\": \"ACTIVE\",\n \"sourceMeterId\": \"100200300\",\n \"targetMeterId\": \"98765456\",\n \"inverterId\": \"inv-12345\",\n \"contractedQuantity\": 10.0,\n \"tradeStartTime\": \"2024-10-04T10:00:00Z\",\n \"tradeEndTime\": \"2024-10-04T18:00:00Z\",\n \"sourceType\": \"SOLAR\",\n \"certification\": {\n \"status\": \"Carbon Offset Certified\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert.pdf\"\n ]\n },\n \"settlementCycles\": [\n {\n \"cycleId\": \"settle-2024-10-04-001\",\n \"startTime\": \"2024-10-04T00:00:00Z\",\n \"endTime\": \"2024-10-04T23:59:59Z\",\n \"status\": \"PENDING\",\n \"amount\": 0.0,\n \"currency\": \"USD\"\n }\n ]\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_confirm", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_confirm" - ] - }, - "description": "Response to confirm request with activated contract (ACTIVE status) and initialized settlement cycle." - }, - "response": [] - } - ] - }, - { - "name": "on_status", - "item": [ - { - "name": "on_status-energy-delivery-in-progress", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\",\n \"beckn:state\": {\n \"@type\": \"beckn:State\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"IN_PROGRESS\"\n }\n },\n \"beckn:attributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"IN_PROGRESS\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 9.8,\n \"deliveryStartTime\": \"2024-10-04T10:00:00Z\",\n \"deliveryEndTime\": null,\n \"meterReadings\": [\n {\n \"timestamp\": \"2024-10-04T10:00:00Z\",\n \"sourceReading\": 1000.0,\n \"targetReading\": 990.0,\n \"energyFlow\": 10.0\n },\n {\n \"timestamp\": \"2024-10-04T12:00:00Z\",\n \"sourceReading\": 1000.5,\n \"targetReading\": 990.3,\n \"energyFlow\": 10.2\n },\n {\n \"timestamp\": \"2024-10-04T14:00:00Z\",\n \"sourceReading\": 1001.0,\n \"targetReading\": 990.8,\n \"energyFlow\": 10.2\n }\n ],\n \"telemetry\": [\n {\n \"eventTime\": \"2024-10-04T12:00:00Z\",\n \"metrics\": [\n {\n \"name\": \"ENERGY\",\n \"value\": 5.8,\n \"unitCode\": \"KWH\"\n },\n {\n \"name\": \"POWER\",\n \"value\": 2.5,\n \"unitCode\": \"KW\"\n },\n {\n \"name\": \"VOLTAGE\",\n \"value\": 240.0,\n \"unitCode\": \"VLT\"\n }\n ]\n }\n ],\n \"settlementCycleId\": \"settle-2024-10-04-001\",\n \"lastUpdated\": \"2024-10-04T15:30:00Z\"\n }\n }\n ],\n \"beckn:payments\": [\n {\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-energy-001\",\n \"beckn:type\": \"ON-FULFILLMENT\",\n \"beckn:status\": \"NOT-PAID\",\n \"beckn:collected_by\": \"BPP\"\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeContract\",\n \"contractStatus\": \"ACTIVE\",\n \"sourceMeterId\": \"100200300\",\n \"targetMeterId\": \"98765456\",\n \"inverterId\": \"inv-12345\",\n \"contractedQuantity\": 10.0,\n \"tradeStartTime\": \"2024-10-04T10:00:00Z\",\n \"tradeEndTime\": \"2024-10-04T18:00:00Z\",\n \"sourceType\": \"SOLAR\",\n \"certification\": {\n \"status\": \"Carbon Offset Certified\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert.pdf\"\n ]\n },\n \"settlementCycles\": [\n {\n \"cycleId\": \"settle-2024-10-04-001\",\n \"startTime\": \"2024-10-04T00:00:00Z\",\n \"endTime\": \"2024-10-04T23:59:59Z\",\n \"status\": \"PENDING\",\n \"amount\": 0.0,\n \"currency\": \"USD\"\n }\n ],\n \"lastUpdated\": \"2024-10-04T15:30:00Z\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_status", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_status" - ] - }, - "description": "Response to status request during delivery with IN_PROGRESS status, meter readings, and telemetry data." - }, - "response": [] - }, - { - "name": "on_status-energy-delivery-completed", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_status\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{transaction_id}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-energy-001\",\n \"beckn:items\": [\n {\n \"beckn:id\": \"energy-resource-solar-001\",\n \"quantity\": {\n \"count\": 10.0,\n \"unit\": \"kWh\"\n }\n }\n ],\n \"beckn:offers\": [\n {\n \"beckn:id\": \"offer-energy-001\"\n }\n ],\n \"beckn:provider\": {\n \"beckn:id\": \"provider-solar-farm-001\"\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-energy-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\",\n \"beckn:state\": {\n \"@type\": \"beckn:State\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"COMPLETED\"\n }\n },\n \"beckn:attributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeDelivery/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeDelivery\",\n \"deliveryStatus\": \"COMPLETED\",\n \"deliveryMode\": \"GRID_INJECTION\",\n \"deliveredQuantity\": 10.0,\n \"deliveryStartTime\": \"2024-10-04T10:00:00Z\",\n \"deliveryEndTime\": \"2024-10-04T18:00:00Z\",\n \"meterReadings\": [\n {\n \"timestamp\": \"2024-10-04T10:00:00Z\",\n \"sourceReading\": 1000.0,\n \"targetReading\": 990.0,\n \"energyFlow\": 0.0\n },\n {\n \"timestamp\": \"2024-10-04T12:00:00Z\",\n \"sourceReading\": 1000.5,\n \"targetReading\": 990.3,\n \"energyFlow\": 0.3\n },\n {\n \"timestamp\": \"2024-10-04T14:00:00Z\",\n \"sourceReading\": 1001.0,\n \"targetReading\": 990.8,\n \"energyFlow\": 0.5\n },\n {\n \"timestamp\": \"2024-10-04T16:00:00Z\",\n \"sourceReading\": 1002.0,\n \"targetReading\": 991.5,\n \"energyFlow\": 0.7\n },\n {\n \"timestamp\": \"2024-10-04T18:00:00Z\",\n \"sourceReading\": 1010.0,\n \"targetReading\": 1000.0,\n \"energyFlow\": 10.0\n }\n ],\n \"telemetry\": [\n {\n \"eventTime\": \"2024-10-04T18:00:00Z\",\n \"metrics\": [\n {\n \"name\": \"ENERGY\",\n \"value\": 10.0,\n \"unitCode\": \"KWH\"\n },\n {\n \"name\": \"POWER\",\n \"value\": 0.0,\n \"unitCode\": \"KW\"\n },\n {\n \"name\": \"VOLTAGE\",\n \"value\": 240.0,\n \"unitCode\": \"VLT\"\n }\n ]\n }\n ],\n \"settlementCycleId\": \"settle-2024-10-04-001\",\n \"lastUpdated\": \"2024-10-04T18:30:00Z\"\n }\n }\n ],\n \"beckn:payments\": [\n {\n \"@type\": \"beckn:Payment\",\n \"beckn:id\": \"payment-energy-001\",\n \"beckn:type\": \"ON-FULFILLMENT\",\n \"beckn:status\": \"NOT-PAID\",\n \"beckn:collected_by\": \"BPP\"\n }\n ],\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeContract\",\n \"contractStatus\": \"COMPLETED\",\n \"sourceMeterId\": \"100200300\",\n \"targetMeterId\": \"98765456\",\n \"inverterId\": \"inv-12345\",\n \"contractedQuantity\": 10.0,\n \"tradeStartTime\": \"2024-10-04T10:00:00Z\",\n \"tradeEndTime\": \"2024-10-04T18:00:00Z\",\n \"sourceType\": \"SOLAR\",\n \"certification\": {\n \"status\": \"Carbon Offset Certified\",\n \"certificates\": [\n \"https://example.com/certs/solar-panel-cert.pdf\"\n ]\n },\n \"settlementCycles\": [\n {\n \"cycleId\": \"settle-2024-10-04-001\",\n \"startTime\": \"2024-10-04T00:00:00Z\",\n \"endTime\": \"2024-10-04T23:59:59Z\",\n \"status\": \"SETTLED\",\n \"amount\": 4.0,\n \"currency\": \"USD\",\n \"breakdown\": {\n \"energyCost\": 1.5,\n \"wheelingCharges\": 2.5\n }\n }\n ],\n \"lastUpdated\": \"2024-10-04T18:30:00Z\"\n }\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_status", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_status" - ] - }, - "description": "Response to status request after delivery completion with COMPLETED status, final meter readings, and SETTLED settlement cycle." - }, - "response": [] - } - ] - }, - { - "name": "cascaded-on_init", - "item": [ - { - "name": "cascaded-on_init-utility", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"context\": {\n \"version\": \"{{version}}\",\n \"action\": \"on_init\",\n \"timestamp\": \"{{iso_date}}\",\n \"message_id\": \"{{$guid}}\",\n \"transaction_id\": \"{{cascaded_transaction_id}}\",\n \"bap_id\": \"{{cascaded_bap_id}}\",\n \"bap_uri\": \"{{cascaded_bap_uri}}\",\n \"bpp_id\": \"{{cascaded_bpp_id}}\",\n \"bpp_uri\": \"{{cascaded_bpp_uri}}\",\n \"ttl\": \"PT30S\",\n \"domain\": \"{{domain}}\"\n },\n \"message\": {\n \"order\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/core/v2/context.jsonld\",\n \"@type\": \"beckn:Order\",\n \"beckn:id\": \"order-cascaded-utility-001\",\n \"beckn:provider\": {\n \"@type\": \"beckn:Provider\",\n \"beckn:id\": \"provider-uppcl-001\",\n \"beckn:descriptor\": {\n \"@type\": \"beckn:Descriptor\",\n \"schema:name\": \"UPPCL\"\n }\n },\n \"beckn:fulfillments\": [\n {\n \"@type\": \"beckn:Fulfillment\",\n \"beckn:id\": \"fulfillment-utility-registration-001\",\n \"beckn:type\": \"ENERGY_DELIVERY\",\n \"beckn:customer\": {\n \"@type\": \"beckn:Customer\",\n \"beckn:person\": {\n \"@type\": \"schema:Person\",\n \"schema:name\": \"Raj\"\n },\n \"beckn:contact\": {\n \"@type\": \"schema:ContactPoint\",\n \"schema:telephone\": \"+91-1276522222\"\n }\n },\n \"beckn:stops\": [\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-source-utility-001\",\n \"beckn:type\": \"START\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"92982739\"\n }\n },\n {\n \"@type\": \"beckn:Stop\",\n \"beckn:id\": \"stop-target-utility-001\",\n \"beckn:type\": \"END\",\n \"beckn:location\": {\n \"@type\": \"beckn:Location\",\n \"beckn:address\": \"98765456\"\n }\n }\n ]\n }\n ],\n \"beckn:quote\": {\n \"@type\": \"beckn:Quotation\",\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 2.5,\n \"schema:priceCurrency\": \"INR\"\n },\n \"beckn:breakup\": [\n {\n \"@type\": \"beckn:Breakup\",\n \"beckn:title\": \"Wheeling Charge\",\n \"beckn:price\": {\n \"@type\": \"schema:PriceSpecification\",\n \"schema:price\": 2.5,\n \"schema:priceCurrency\": \"INR\"\n }\n }\n ]\n },\n \"beckn:orderAttributes\": {\n \"@context\": \"https://raw.githubusercontent.com/beckn/protocol-specifications-new/refs/heads/draft/schema/EnergyTradeContract/v0.2/context.jsonld\",\n \"@type\": \"EnergyTradeContract\",\n \"contractStatus\": \"PENDING\",\n \"sourceMeterId\": \"92982739\",\n \"targetMeterId\": \"98765456\",\n \"contractedQuantity\": 10.0,\n \"tradeStartTime\": \"2024-10-04T10:00:00Z\",\n \"tradeEndTime\": \"2024-10-04T18:00:00Z\",\n \"sourceType\": \"SOLAR\"\n },\n \"beckn:billing\": {\n \"@type\": \"beckn:Billing\",\n \"beckn:name\": \"p2p-Trading-BPP\",\n \"beckn:email\": \"p2ptbpp@example.com\",\n \"beckn:phone\": \"+91-1276522222\"\n },\n \"beckn:cancellationTerms\": [\n {\n \"@type\": \"beckn:CancellationTerm\",\n \"beckn:externalRef\": {\n \"@type\": \"schema:MediaObject\",\n \"schema:encodingFormat\": \"text/html\",\n \"schema:contentUrl\": \"https://mvvnl.in/cancellation_terms.html\"\n }\n }\n ]\n }\n }\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "{{bpp_adapter_url}}/on_init", - "host": [ - "{{bpp_adapter_url}}" - ], - "path": [ - "on_init" - ] - }, - "description": "Response from Utility Company (Transmission BPP) to cascaded init request with wheeling charges quote." - }, - "response": [] - } - ] - } - ], - "event": [ - { - "listen": "prerequest", - "script": { - "type": "text/javascript", - "exec": [ - "// Pure JS pre-request script to replace moment()", - "", - "// 1) ISO 8601 timestamp without needing moment", - "const isoTimestamp = new Date().toISOString();", - "pm.collectionVariables.set('iso_date', isoTimestamp);" - ] - } - } - ], - "variable": [ - { - "key": "domain", - "value": "energy-trade" - }, - { - "key": "version", - "value": "2.0.0" - }, - { - "key": "bap_id", - "value": "bap.energy-consumer.com" - }, - { - "key": "bap_uri", - "value": "https://bap.energy-consumer.com" - }, - { - "key": "bpp_id", - "value": "bpp.energy-provider.com" - }, - { - "key": "bpp_uri", - "value": "https://bpp.energy-provider.com" - }, - { - "key": "bpp_adapter_url", - "value": "http://localhost:3002/api/webhook/trigger" - }, - { - "key": "transaction_id", - "value": "txn-energy-001" - }, - { - "key": "cascaded_transaction_id", - "value": "txn-cascaded-energy-001" - }, - { - "key": "cascaded_bap_id", - "value": "p2pTrading-bpp.com" - }, - { - "key": "cascaded_bap_uri", - "value": "https://api.p2pTrading-bpp.com/pilot/bap/energy/v2" - }, - { - "key": "cascaded_bpp_id", - "value": "example-transmission-bpp.com" - }, - { - "key": "cascaded_bpp_uri", - "value": "https://api.example-transmission-bpp.com/pilot/bpp/" - }, - { - "key": "iso_date", - "value": "" - } - ] -}