{
  "openapi": "3.1.0",
  "info": {
    "title": "EnergyFi API — sandbox",
    "version": "0.2.0",
    "summary": "Verifiable energy cash flows: telemetry ingest, projects, distributions, evidence.",
    "description": "Sandbox fixtures. Values are fixed sample data, not measurements from a real plant.\n\nThis document describes the routes the sandbox actually implements. The\nfull interface described at https://energyfi.arkreen.com/docs/ is wider;\nendpoints not listed here are not callable yet.\n\nDevice signing is referenced by the telemetry endpoint but its production\nrules — transport, canonical serialisation, algorithm, key rotation — are\nnot yet published. The sandbox does not verify signatures.",
    "contact": {
      "name": "EnergyFi",
      "email": "energyfi@arkreen.com",
      "url": "https://energyfi.arkreen.com/"
    },
    "license": {
      "name": "Proprietary — Arkreen Network",
      "url": "https://energyfi.arkreen.com/docs/"
    }
  },
  "servers": [
    {
      "url": "https://sandbox.api.arkreen.com/v1",
      "description": "Sandbox (fixture-backed)"
    }
  ],
  "tags": [
    {
      "name": "Auth",
      "description": "Obtaining a bearer token."
    },
    {
      "name": "Assets",
      "description": "Projects and the devices that meter them."
    },
    {
      "name": "Ingest",
      "description": "Submitting meter readings."
    },
    {
      "name": "Settlement",
      "description": "Distributions, their waterfall, and webhooks."
    },
    {
      "name": "Evidence",
      "description": "Resolving an evidence_ref to its four clusters."
    },
    {
      "name": "Meta",
      "description": "Environment, capabilities, and this document."
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Token from POST /auth/token."
      }
    },
    "schemas": {
      "Reading": {
        "type": "object",
        "required": [
          "device_ts",
          "energy_wh_cumulative",
          "meter_epoch",
          "sequence_number",
          "reading_id"
        ],
        "properties": {
          "device_ts": {
            "type": "string",
            "format": "date-time",
            "description": "RFC 3339. Drift beyond ±300 s is flagged, not rejected."
          },
          "energy_wh_cumulative": {
            "type": "integer",
            "description": "Lifetime counter. Monotonic within a meter_epoch only."
          },
          "meter_epoch": {
            "type": "integer",
            "description": "Increments on meter replacement or counter reset."
          },
          "sequence_number": {
            "type": "integer",
            "description": "Monotonic per device."
          },
          "reading_id": {
            "type": "string"
          },
          "reset_reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "power_cycle",
              "firmware",
              "meter_swap",
              "unknown",
              null
            ]
          },
          "measurement_quality": {
            "type": "string",
            "enum": [
              "good",
              "estimated",
              "degraded"
            ]
          },
          "supersedes_reading_id": {
            "type": "string",
            "description": "Set when correcting a previously accepted reading."
          },
          "active_power_w": {
            "type": "integer"
          }
        }
      },
      "TelemetryBatch": {
        "type": "object",
        "required": [
          "device_id",
          "readings"
        ],
        "properties": {
          "device_id": {
            "type": "string"
          },
          "readings": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Reading"
            }
          }
        }
      },
      "BatchAccepted": {
        "type": "object",
        "properties": {
          "accepted": {
            "type": "integer"
          },
          "rejected": {
            "type": "integer"
          },
          "batch_id": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "verification": {
            "type": "object",
            "properties": {
              "signature": {
                "type": "string",
                "enum": [
                  "valid",
                  "invalid",
                  "absent"
                ],
                "description": "Synchronous — decidable on receipt."
              },
              "continuity": {
                "type": "string",
                "enum": [
                  "ok",
                  "gap",
                  "regression"
                ]
              },
              "anomaly_score": {
                "type": "number"
              },
              "anomaly_status": {
                "type": "string",
                "enum": [
                  "provisional",
                  "confirmed"
                ]
              }
            }
          },
          "attestation": {
            "type": "object",
            "description": "Anchoring is asynchronous; a 200 does not mean anchored.",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "pending",
                  "anchored",
                  "failed"
                ]
              },
              "expected_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "Project": {
        "type": "object",
        "example": {
          "project_id": "prj_sandbox_th01",
          "name": "Rooftop — Chonburi Industrial Park",
          "data_assurance": "L3",
          "asset_readiness": "investment_ready",
          "assurance_state": "active",
          "status": "operating",
          "installed_capacity_w": 300000,
          "lifetime_generation_wh": 700320000,
          "performance_ratio": 0.841,
          "chain_refs": {
            "chain": "polygon-amoy",
            "unit_token": {
              "token_id": "8442"
            }
          }
        }
      },
      "Device": {
        "type": "object",
        "example": {
          "device_id": "dev_sandbox_m3",
          "project_id": "prj_sandbox_th01",
          "meter_epoch": 2,
          "last_sequence_number": 88214,
          "last_energy_wh_cumulative": 700320000,
          "baseline_complete": true
        }
      },
      "Distribution": {
        "type": "object",
        "example": {
          "distribution_id": "dst_sandbox_4mB7xQ",
          "project_id": "prj_sandbox_th01",
          "epoch": 71204,
          "status": "executed",
          "currency": "USDC",
          "gross_minor": 164140,
          "waterfall": [
            {
              "leg": "opex_reserve",
              "amount_minor": 31590
            },
            {
              "leg": "operator",
              "amount_minor": 9421
            },
            {
              "leg": "protocol_fee",
              "amount_minor": 3129
            },
            {
              "leg": "unit_holders",
              "amount_minor": 120000
            }
          ],
          "per_unit_minor": 40,
          "evidence_ref": "evd_sandbox_6Rk9wT"
        }
      },
      "Evidence": {
        "type": "object",
        "example": {
          "evidence_ref": "evd_sandbox_6Rk9wT",
          "project_id": "prj_sandbox_th01",
          "distribution_id": "dst_sandbox_4mB7xQ",
          "clusters": {
            "energy_evidence": {
              "readings": 4464,
              "merkle_root": "0x8f3c1d0a5b7e2f9c4d6a8b1e3f5c7d9a0b2e4f6c8d1a3b5e7f9c0d2a4b6e8f3e",
              "anchor": {
                "chain": "polygon-amoy",
                "tx": "0x8f…3e21",
                "status": "anchored"
              }
            },
            "legal_evidence": {
              "documents": [
                "doc_5nT2",
                "doc_8vJ4"
              ],
              "status": "verified"
            },
            "settlement_evidence": {
              "bank_confirmation": "doc_1cZ6",
              "status": "confirmed"
            },
            "distribution_evidence": {
              "audit_trail": "adt_9qH4",
              "status": "complete"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": [
          "Meta"
        ],
        "summary": "Liveness",
        "security": [],
        "responses": {
          "200": {
            "description": "ok"
          },
          "404": {
            "description": "No such resource in the sandbox",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "not_found",
                    "message": "No such resource in the sandbox"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/version": {
      "get": {
        "tags": [
          "Meta"
        ],
        "summary": "Spec version",
        "security": [],
        "responses": {
          "200": {
            "description": "ok"
          },
          "404": {
            "description": "No such resource in the sandbox",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "not_found",
                    "message": "No such resource in the sandbox"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/capabilities": {
      "get": {
        "tags": [
          "Meta"
        ],
        "security": [],
        "summary": "What this environment implements, simulates, and omits",
        "responses": {
          "200": {
            "description": "Capability report"
          },
          "404": {
            "description": "No such resource in the sandbox",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "not_found",
                    "message": "No such resource in the sandbox"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/auth/token": {
      "post": {
        "tags": [
          "Auth"
        ],
        "security": [],
        "summary": "Exchange client credentials for a bearer token",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type",
                  "client_id",
                  "client_secret"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "client_credentials"
                    ]
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "client_secret": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token issued",
            "content": {
              "application/json": {
                "example": {
                  "access_token": "sbx_…",
                  "token_type": "Bearer",
                  "expires_in": 3600
                }
              }
            }
          },
          "400": {
            "description": "Request body failed validation",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "invalid_request",
                    "message": "Request body failed validation"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/projects/{project_id}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Fetch a project",
        "parameters": [
          {
            "name": "project_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "prj_sandbox_th01"
          }
        ],
        "responses": {
          "200": {
            "description": "Project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                },
                "example": {
                  "project_id": "prj_sandbox_th01",
                  "name": "Rooftop — Chonburi Industrial Park",
                  "data_assurance": "L3",
                  "asset_readiness": "investment_ready",
                  "assurance_state": "active",
                  "status": "operating",
                  "installed_capacity_w": 300000,
                  "lifetime_generation_wh": 700320000,
                  "performance_ratio": 0.841,
                  "chain_refs": {
                    "chain": "polygon-amoy",
                    "unit_token": {
                      "token_id": "8442"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "unauthorized",
                    "message": "Missing or invalid bearer token"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "404": {
            "description": "No such resource in the sandbox",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "not_found",
                    "message": "No such resource in the sandbox"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/devices/{device_id}": {
      "get": {
        "tags": [
          "Assets"
        ],
        "summary": "Fetch a device",
        "parameters": [
          {
            "name": "device_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "dev_sandbox_m3"
          }
        ],
        "responses": {
          "200": {
            "description": "Device",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Device"
                },
                "example": {
                  "device_id": "dev_sandbox_m3",
                  "project_id": "prj_sandbox_th01",
                  "meter_epoch": 2,
                  "last_sequence_number": 88214,
                  "last_energy_wh_cumulative": 700320000,
                  "baseline_complete": true
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "unauthorized",
                    "message": "Missing or invalid bearer token"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or deregistered device_id",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "device_not_found",
                    "message": "Unknown or deregistered device_id"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/telemetry:batch": {
      "post": {
        "tags": [
          "Ingest"
        ],
        "summary": "Submit signed meter readings for a registered device",
        "description": "Returns 200, not 202. Anchoring is asynchronous under attestation.{status,expected_at}; the anomaly score is provisional.",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Replaying a key returns the original body."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TelemetryBatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchAccepted"
                }
              }
            }
          },
          "401": {
            "description": "Signature failed verification against the registered public key",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "signature_invalid",
                    "message": "Signature failed verification against the registered public key"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or deregistered device_id",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "device_not_found",
                    "message": "Unknown or deregistered device_id"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "409": {
            "description": "Device still in its baseline window; readings stored but not attested",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "baseline_incomplete",
                    "message": "Device still in its baseline window; readings stored but not attested"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "422": {
            "description": "Cumulative value below the last accepted reading in the same meter_epoch",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "counter_regression",
                    "message": "Cumulative value below the last accepted reading in the same meter_epoch"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/distributions/{distribution_id}": {
      "get": {
        "tags": [
          "Settlement"
        ],
        "summary": "Fetch a distribution and its waterfall",
        "parameters": [
          {
            "name": "distribution_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "dst_sandbox_4mB7xQ"
          }
        ],
        "responses": {
          "200": {
            "description": "Distribution",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Distribution"
                },
                "example": {
                  "distribution_id": "dst_sandbox_4mB7xQ",
                  "project_id": "prj_sandbox_th01",
                  "epoch": 71204,
                  "status": "executed",
                  "currency": "USDC",
                  "gross_minor": 164140,
                  "waterfall": [
                    {
                      "leg": "opex_reserve",
                      "amount_minor": 31590
                    },
                    {
                      "leg": "operator",
                      "amount_minor": 9421
                    },
                    {
                      "leg": "protocol_fee",
                      "amount_minor": 3129
                    },
                    {
                      "leg": "unit_holders",
                      "amount_minor": 120000
                    }
                  ],
                  "per_unit_minor": 40,
                  "evidence_ref": "evd_sandbox_6Rk9wT"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "unauthorized",
                    "message": "Missing or invalid bearer token"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "404": {
            "description": "No such resource in the sandbox",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "not_found",
                    "message": "No such resource in the sandbox"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/evidence/{evidence_ref}": {
      "get": {
        "tags": [
          "Evidence"
        ],
        "summary": "Resolve an evidence reference to its four clusters",
        "parameters": [
          {
            "name": "evidence_ref",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "evd_sandbox_6Rk9wT"
          }
        ],
        "responses": {
          "200": {
            "description": "Evidence",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Evidence"
                },
                "example": {
                  "evidence_ref": "evd_sandbox_6Rk9wT",
                  "project_id": "prj_sandbox_th01",
                  "distribution_id": "dst_sandbox_4mB7xQ",
                  "clusters": {
                    "energy_evidence": {
                      "readings": 4464,
                      "merkle_root": "0x8f3c1d0a5b7e2f9c4d6a8b1e3f5c7d9a0b2e4f6c8d1a3b5e7f9c0d2a4b6e8f3e",
                      "anchor": {
                        "chain": "polygon-amoy",
                        "tx": "0x8f…3e21",
                        "status": "anchored"
                      }
                    },
                    "legal_evidence": {
                      "documents": [
                        "doc_5nT2",
                        "doc_8vJ4"
                      ],
                      "status": "verified"
                    },
                    "settlement_evidence": {
                      "bank_confirmation": "doc_1cZ6",
                      "status": "confirmed"
                    },
                    "distribution_evidence": {
                      "audit_trail": "adt_9qH4",
                      "status": "complete"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "unauthorized",
                    "message": "Missing or invalid bearer token"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "404": {
            "description": "No such resource in the sandbox",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "not_found",
                    "message": "No such resource in the sandbox"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks": {
      "post": {
        "tags": [
          "Settlement"
        ],
        "summary": "Register a webhook endpoint",
        "description": "The sandbox never delivers. Registration is echoed back only.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "events"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "distribution.executed",
                        "assurance.provisionally_downgraded",
                        "assurance.restored",
                        "telemetry.anomaly_detected"
                      ]
                    }
                  }
                }
              },
              "example": {
                "url": "https://example.com/hooks/arkreen",
                "events": [
                  "distribution.executed",
                  "assurance.provisionally_downgraded",
                  "assurance.restored",
                  "telemetry.anomaly_detected"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registered"
          },
          "400": {
            "description": "Request body failed validation",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "invalid_request",
                    "message": "Request body failed validation"
                  },
                  "environment": "sandbox"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token",
            "content": {
              "application/json": {
                "example": {
                  "error": {
                    "ark_code": "unauthorized",
                    "message": "Missing or invalid bearer token"
                  },
                  "environment": "sandbox"
                }
              }
            }
          }
        }
      }
    }
  }
}
