{
  "openapi": "3.1.0",
  "info": {
    "title": "ChainsFlow Public API",
    "version": "1.4.0",
    "description": "Build read-only exchange portfolio experiences without handling provider-specific balance formats.\n\n## Authentication\n\nCreate a personal API key in the ChainsFlow developer dashboard and send it in every request:\n\n```http\nX-API-Key: cf_live_your_api_key\n```\n\nKeys are shown once, stored only as hashes, and must never be exposed in browser or mobile client code.\n\n## Credits and rate limits\n\nSuccessful metered responses include `X-Credit-Cost` and `X-Credits-Remaining`. Failed requests refund their reservation and return `X-Credit-Cost: 0`. Rate-limited responses use HTTP `429` with an integer-seconds `Retry-After` header.\n\n## Data safety\n\nExchange credentials must be read-only. ChainsFlow never requires trading or withdrawal permissions.",
    "contact": {
      "name": "ChainsFlow API",
      "url": "https://api.chainsflow.com"
    }
  },
  "servers": [
    {
      "url": "https://api.chainsflow.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "personalToken": []
    }
  ],
  "tags": [
    {
      "name": "Portfolios",
      "description": "Connect read-only exchange portfolios and manage them by portfolio ID."
    },
    {
      "name": "Portfolio overview",
      "description": "Read aggregate values for all portfolios or an explicit portfolio subset."
    },
    {
      "name": "Exchange data",
      "description": "Read synchronization state, transactions, charts, and performance for one portfolio."
    },
    {
      "name": "Usage & credits",
      "description": "Inspect the current API credit balance, published operation weights, and the append-only credit ledger."
    }
  ],
  "x-tagGroups": [
    {
      "name": "Public API",
      "tags": [
        "Portfolios",
        "Portfolio overview",
        "Exchange data",
        "Usage & credits"
      ]
    }
  ],
  "paths": {
    "/api/v1/portfolio": {
      "get": {
        "operationId": "getPortfolioOverview",
        "tags": [
          "Portfolio overview"
        ],
        "summary": "Get the aggregated portfolio overview",
        "description": "The 24-hour fields are a market-implied estimate from current holdings and asset price changes, not transaction-aware P&L.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioIds"
          }
        ],
        "responses": {
          "200": {
            "description": "Aggregate USD totals and asset positions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioOverview"
                }
              }
            }
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolio' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolio/performance": {
      "get": {
        "operationId": "getPortfolioPerformance",
        "tags": [
          "Portfolio overview"
        ],
        "summary": "Get tracked portfolio history and cash-flow-adjusted P&L",
        "description": "Returns server-side value snapshots and adjusts P&L for detected deposits, withdrawals, and connection-scope changes. Inspect coverage before presenting the result as complete.",
        "parameters": [
          {
            "name": "range",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "7D",
                "30D",
                "90D",
                "1Y",
                "ALL"
              ],
              "default": "30D"
            }
          },
          {
            "$ref": "#/components/parameters/PortfolioIds"
          }
        ],
        "responses": {
          "200": {
            "description": "Portfolio performance over the requested tracking range",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioPerformance"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolio/performance' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolios": {
      "get": {
        "operationId": "listPortfolioConnections",
        "tags": [
          "Portfolios"
        ],
        "summary": "List exchange portfolio connections",
        "responses": {
          "200": {
            "description": "Portfolio connections",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Portfolio"
                  }
                }
              }
            }
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      },
      "post": {
        "operationId": "createPortfolioConnection",
        "tags": [
          "Portfolios"
        ],
        "summary": "Create and initially synchronize an exchange portfolio",
        "description": "API credentials must have balance-reading permissions only.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePortfolioRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Connected and synchronized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Portfolio"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "409": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "$ref": "#/components/responses/Problem"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY' \\\n  --header 'Content-Type: application/json' \\\n  --data @request.json"
          }
        ]
      }
    },
    "/api/v1/portfolios/batch": {
      "post": {
        "operationId": "getPortfolioConnectionsBatch",
        "tags": [
          "Portfolios"
        ],
        "summary": "Get up to 100 portfolios by ID",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "portfolioIds"
                ],
                "properties": {
                  "portfolioIds": {
                    "type": "array",
                    "maxItems": 100,
                    "uniqueItems": true,
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accessible matching portfolios",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Portfolio"
                  }
                }
              }
            }
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request POST \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/batch' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY' \\\n  --header 'Content-Type: application/json' \\\n  --data @request.json"
          }
        ]
      }
    },
    "/api/v1/portfolios/{portfolioId}": {
      "get": {
        "operationId": "getPortfolioConnection",
        "tags": [
          "Portfolios"
        ],
        "summary": "Get a portfolio connection",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          }
        ],
        "responses": {
          "200": {
            "description": "Portfolio",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Portfolio"
                }
              }
            }
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "404": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      },
      "delete": {
        "operationId": "deletePortfolioConnection",
        "tags": [
          "Portfolios"
        ],
        "summary": "Remove a portfolio and its balances",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "404": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request DELETE \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolios/{portfolioId}/balances": {
      "get": {
        "operationId": "getPortfolioBalances",
        "tags": [
          "Portfolios"
        ],
        "summary": "Get the latest normalized balances reported by the exchange",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          },
          {
            "$ref": "#/components/parameters/WalletTypes"
          }
        ],
        "responses": {
          "200": {
            "description": "Balances",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Balance"
                  }
                }
              }
            }
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>/balances' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolios/{portfolioId}/sync": {
      "patch": {
        "operationId": "synchronizePortfolioConnection",
        "tags": [
          "Portfolios"
        ],
        "summary": "Enqueue a portfolio synchronization",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          }
        ],
        "responses": {
          "200": {
            "description": "Portfolio status after the synchronization was queued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Portfolio"
                }
              }
            }
          },
          "402": {
            "$ref": "#/components/responses/InsufficientCredits"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request PATCH \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>/sync' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/usage/credits": {
      "get": {
        "operationId": "getApiCreditUsage",
        "tags": [
          "Usage & credits"
        ],
        "summary": "Get the current credit balance and dynamic cost definitions",
        "description": "This endpoint is free and never consumes credits.",
        "x-credit-base-cost": 0,
        "responses": {
          "200": {
            "description": "Credit balance and cost catalogue",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditUsageEnvelope"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/usage/credits' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/usage/credits/history": {
      "get": {
        "operationId": "getApiCreditHistory",
        "tags": [
          "Usage & credits"
        ],
        "summary": "Read the append-only credit ledger",
        "description": "Returns grants, purchases, debits, refunds and operator adjustments. This endpoint is free.",
        "x-credit-base-cost": 0,
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Most recent credit movements",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditHistoryEnvelope"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/usage/credits/history' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolios/{portfolioId}/sync-status": {
      "get": {
        "operationId": "getPortfolioConnectionSyncStatus",
        "tags": [
          "Exchange data"
        ],
        "summary": "Read synchronization state for a portfolio connection",
        "x-credit-base-cost": 1,
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          }
        ],
        "responses": {
          "200": {
            "description": "Connection synchronization state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SyncStatus"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>/sync-status' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolios/{portfolioId}/transactions": {
      "get": {
        "operationId": "listPortfolioTransactions",
        "tags": [
          "Portfolios"
        ],
        "summary": "List normalized transactions for one portfolio",
        "x-credit-base-cost": 2,
        "x-credit-multiplier": "PAGE_SIZE",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Connection transactions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortfolioTransactionPage"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>/transactions' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolios/{portfolioId}/chart": {
      "get": {
        "operationId": "getPortfolioConnectionValueChart",
        "tags": [
          "Exchange data"
        ],
        "summary": "Read historical value for one portfolio connection",
        "x-credit-base-cost": 5,
        "x-credit-multiplier": "HISTORY_RANGE",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          },
          {
            "$ref": "#/components/parameters/MarketRange"
          }
        ],
        "responses": {
          "200": {
            "description": "Connection value chart",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValueChart"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>/chart' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    },
    "/api/v1/portfolios/{portfolioId}/performance": {
      "get": {
        "operationId": "getPortfolioConnectionPerformance",
        "tags": [
          "Exchange data"
        ],
        "summary": "Calculate value change for one exchange connection",
        "description": "Uses retained connection snapshots and is separate from cash-flow-adjusted aggregate portfolio performance.",
        "x-credit-base-cost": 5,
        "x-credit-multiplier": "HISTORY_RANGE",
        "parameters": [
          {
            "$ref": "#/components/parameters/PortfolioId"
          },
          {
            "$ref": "#/components/parameters/MarketRange"
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot-based exchange connection performance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfitLossSummary"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/Problem"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "security": [
          {
            "personalToken": []
          }
        ],
        "x-codeSamples": [
          {
            "lang": "curl",
            "label": "cURL",
            "source": "curl --request GET \\\n  --url 'https://api.chainsflow.com/api/v1/portfolios/<portfolioId>/performance' \\\n  --header 'X-API-Key: $CHAINSFLOW_API_KEY'"
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "personalToken": {
        "description": "Personal `cf_live_` key sent in the `X-API-Key` header."
      }
    },
    "responses": {
      "RateLimited": {
        "description": "An application request budget or synchronization cooldown was exceeded.",
        "headers": {
          "Retry-After": {
            "description": "Minimum number of seconds before the caller should retry.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "Problem": {
        "description": "Problem details",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      },
      "InsufficientCredits": {
        "description": "The developer account cannot cover this endpoint weight.",
        "headers": {
          "X-Credit-Cost": {
            "description": "Credits required for the attempted endpoint.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          "X-Credits-Remaining": {
            "description": "Current account-level credit balance.",
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "required": [
          "status",
          "code"
        ],
        "properties": {
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "cost": {
            "type": "integer",
            "minimum": 1
          },
          "remaining": {
            "type": "integer",
            "minimum": 0
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "code"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "code": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ProfitLossSummary": {
        "type": "object",
        "required": [
          "sourceId",
          "quoteCurrency",
          "range",
          "coverage",
          "startValue",
          "endValue",
          "change",
          "points"
        ],
        "properties": {
          "sourceId": {
            "type": "string",
            "format": "uuid"
          },
          "quoteCurrency": {
            "type": "string"
          },
          "range": {
            "type": "string"
          },
          "coverage": {
            "type": "string",
            "enum": [
              "NO_DATA",
              "TRACKING_STARTED",
              "COMPLETE"
            ]
          },
          "startValue": {
            "type": "number"
          },
          "endValue": {
            "type": "number"
          },
          "change": {
            "type": "number"
          },
          "changePercent": {
            "type": [
              "number",
              "null"
            ]
          },
          "from": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "to": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "points": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "ValueChart": {
        "type": "object",
        "required": [
          "quoteCurrency",
          "points"
        ],
        "properties": {
          "quoteCurrency": {
            "type": "string"
          },
          "points": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChartPoint"
            }
          }
        }
      },
      "ChartPoint": {
        "type": "object",
        "required": [
          "at",
          "value"
        ],
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "value": {
            "type": "number"
          }
        }
      },
      "PortfolioTransactionPage": {
        "type": "object",
        "required": [
          "items",
          "pagination"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PortfolioTransaction"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": [
          "page",
          "limit",
          "total",
          "hasNext"
        ],
        "properties": {
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "hasNext": {
            "type": "boolean"
          }
        }
      },
      "PortfolioTransaction": {
        "type": "object",
        "required": [
          "id",
          "type",
          "coin",
          "amount",
          "occurredAt"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "accountId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "DEPOSIT",
              "WITHDRAWAL",
              "CONNECTION_ADDED",
              "CONNECTION_REMOVED"
            ]
          },
          "coin": {
            "$ref": "#/components/schemas/CoinReference"
          },
          "amount": {
            "type": "number"
          },
          "valueUsd": {
            "type": [
              "number",
              "null"
            ]
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CoinReference": {
        "type": "object",
        "required": [
          "id",
          "symbol",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "example": "bitcoin"
          },
          "symbol": {
            "type": "string",
            "example": "BTC"
          },
          "name": {
            "type": "string",
            "example": "Bitcoin"
          },
          "iconUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "rank": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          }
        }
      },
      "SyncStatus": {
        "type": "object",
        "required": [
          "portfolioId",
          "status",
          "performanceTrackingStatus",
          "syncAttempts",
          "nextSyncAt",
          "transactionHistoryFrom",
          "transactionSyncAttempts",
          "transactionSyncNextAt"
        ],
        "properties": {
          "portfolioId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "SYNCING",
              "ACTIVE",
              "ERROR"
            ]
          },
          "lastSyncedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "lastErrorCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "performanceTrackingStatus": {
            "type": "string",
            "enum": [
              "TRACKING",
              "PARTIAL",
              "BALANCE_ONLY"
            ]
          },
          "performanceErrorCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "syncAttempts": {
            "type": "integer",
            "minimum": 0
          },
          "nextSyncAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "transactionHistoryFrom": {
            "type": "string",
            "format": "date-time"
          },
          "transactionsSyncedThrough": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "transactionSyncAttempts": {
            "type": "integer",
            "minimum": 0
          },
          "transactionSyncNextAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "CreditHistoryEnvelope": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/CreditHistory"
          }
        }
      },
      "CreditHistory": {
        "type": "object",
        "required": [
          "entries"
        ],
        "properties": {
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreditHistoryEntry"
            }
          }
        }
      },
      "CreditHistoryEntry": {
        "type": "object",
        "required": [
          "id",
          "type",
          "amount",
          "balanceAfter",
          "reference",
          "reason",
          "occurredAt"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "minimum": 1
          },
          "type": {
            "type": "string",
            "enum": [
              "OPENING_BALANCE",
              "INITIAL_GRANT",
              "PURCHASE",
              "USAGE_DEBIT",
              "REFUND",
              "MANUAL_ADJUSTMENT"
            ]
          },
          "amount": {
            "type": "integer"
          },
          "balanceAfter": {
            "type": "integer",
            "minimum": 0
          },
          "reference": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "occurredAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreditUsageEnvelope": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/CreditUsage"
          }
        }
      },
      "CreditUsage": {
        "type": "object",
        "required": [
          "balance",
          "unit",
          "costs"
        ],
        "properties": {
          "balance": {
            "type": "integer",
            "minimum": 0
          },
          "unit": {
            "type": "string",
            "enum": [
              "credit"
            ]
          },
          "costs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreditDefinition"
            }
          }
        }
      },
      "CreditDefinition": {
        "type": "object",
        "required": [
          "operation",
          "method",
          "path",
          "baseCost",
          "maximumCost",
          "multiplier"
        ],
        "properties": {
          "operation": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "baseCost": {
            "type": "integer",
            "minimum": 1
          },
          "maximumCost": {
            "type": "integer",
            "minimum": 1
          },
          "multiplier": {
            "type": "string",
            "enum": [
              "FIXED",
              "PAGE_SIZE",
              "HISTORY_RANGE"
            ]
          }
        }
      },
      "Portfolio": {
        "type": "object",
        "required": [
          "id",
          "exchange",
          "label",
          "status",
          "performanceTrackingStatus",
          "syncAttempts",
          "nextSyncAt"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "exchange": {
            "type": "string",
            "enum": [
              "BINANCE",
              "BYBIT",
              "KRAKEN",
              "OKX"
            ]
          },
          "label": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "SYNCING",
              "ACTIVE",
              "ERROR"
            ]
          },
          "performanceTrackingStatus": {
            "type": "string",
            "enum": [
              "TRACKING",
              "PARTIAL",
              "BALANCE_ONLY"
            ]
          },
          "performanceErrorCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "lastSyncedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "lastErrorCode": {
            "type": [
              "string",
              "null"
            ]
          },
          "syncAttempts": {
            "type": "integer",
            "minimum": 0
          },
          "nextSyncAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Balance": {
        "type": "object",
        "required": [
          "asset",
          "walletType",
          "available",
          "locked"
        ],
        "properties": {
          "asset": {
            "type": "string"
          },
          "walletType": {
            "type": "string",
            "enum": [
              "SPOT",
              "FUNDING",
              "UNIFIED",
              "TRADING"
            ]
          },
          "available": {
            "type": "number"
          },
          "locked": {
            "type": "number"
          }
        }
      },
      "CreatePortfolioRequest": {
        "description": "Canonical exchange connection request.",
        "type": "object",
        "unevaluatedProperties": false,
        "required": [
          "connectionId",
          "connectionFields"
        ],
        "properties": {
          "connectionId": {
            "type": "string",
            "enum": [
              "binance",
              "bybit",
              "kraken",
              "okx"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 80
          },
          "transactionHistoryFrom": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Optional inclusive start of transaction tracking. Defaults to the earliest history supported by the selected exchange at connection time."
          },
          "connectionFields": {
            "$ref": "#/components/schemas/ExchangeConnectionFields"
          }
        }
      },
      "ExchangeConnectionFields": {
        "type": "object",
        "unevaluatedProperties": false,
        "required": [
          "apiKey",
          "apiSecret"
        ],
        "properties": {
          "apiKey": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "writeOnly": true
          },
          "apiSecret": {
            "type": "string",
            "minLength": 1,
            "maxLength": 512,
            "writeOnly": true
          },
          "passphrase": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 512,
            "writeOnly": true
          }
        }
      },
      "PortfolioPerformance": {
        "type": "object",
        "required": [
          "range",
          "coverage",
          "startValueUsd",
          "endValueUsd",
          "points"
        ],
        "properties": {
          "range": {
            "type": "string",
            "enum": [
              "24H",
              "7D",
              "30D",
              "90D",
              "6M",
              "1Y",
              "ALL"
            ]
          },
          "coverage": {
            "type": "string",
            "enum": [
              "NO_DATA",
              "TRACKING_STARTED",
              "COMPLETE",
              "PARTIAL"
            ]
          },
          "trackingStartedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "asOf": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "startValueUsd": {
            "type": "number"
          },
          "endValueUsd": {
            "type": "number"
          },
          "netContributionsUsd": {
            "description": "Signed deposits minus withdrawals when every detected cash flow can be priced.",
            "type": [
              "number",
              "null"
            ]
          },
          "profitLossUsd": {
            "description": "End value minus start value minus net contributions. Treat as estimated unless coverage is COMPLETE.",
            "type": [
              "number",
              "null"
            ]
          },
          "returnPercent": {
            "description": "Modified Dietz return when the denominator and cash-flow pricing are valid.",
            "type": [
              "number",
              "null"
            ]
          },
          "points": {
            "type": "array",
            "maxItems": 120,
            "items": {
              "$ref": "#/components/schemas/PerformancePoint"
            }
          }
        }
      },
      "PerformancePoint": {
        "type": "object",
        "required": [
          "at",
          "valueUsd"
        ],
        "properties": {
          "at": {
            "type": "string",
            "format": "date-time"
          },
          "valueUsd": {
            "type": "number"
          },
          "netContributionsUsd": {
            "type": [
              "number",
              "null"
            ]
          },
          "profitLossUsd": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "PortfolioOverview": {
        "type": "object",
        "required": [
          "totalUsd",
          "change24hUsd",
          "change24hPercent",
          "assets"
        ],
        "properties": {
          "totalUsd": {
            "type": "number"
          },
          "change24hUsd": {
            "type": "number"
          },
          "change24hPercent": {
            "type": "number"
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PortfolioOverviewAsset"
            }
          }
        }
      },
      "PortfolioOverviewAsset": {
        "type": "object",
        "required": [
          "asset",
          "amount",
          "usdPrice",
          "usdValue",
          "allocationPercent",
          "change24hPercent"
        ],
        "properties": {
          "asset": {
            "type": "string"
          },
          "amount": {
            "type": "number"
          },
          "usdPrice": {
            "type": "number"
          },
          "btcPrice": {
            "type": [
              "number",
              "null"
            ]
          },
          "usdValue": {
            "type": "number"
          },
          "allocationPercent": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "change24hPercent": {
            "type": "number"
          }
        }
      }
    },
    "parameters": {
      "MarketRange": {
        "name": "range",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "1h",
            "24h",
            "7d",
            "30d",
            "90d",
            "1y",
            "all"
          ],
          "default": "30d"
        }
      },
      "PortfolioId": {
        "name": "portfolioId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Page cost doubles when requesting 51-100 items.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 50
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "WalletTypes": {
        "name": "walletTypes",
        "in": "query",
        "required": false,
        "description": "Repeat this parameter to filter balances by provider wallet scope.",
        "schema": {
          "type": "array",
          "uniqueItems": true,
          "items": {
            "type": "string",
            "enum": [
              "SPOT",
              "FUNDING",
              "UNIFIED",
              "TRADING"
            ]
          }
        }
      },
      "PortfolioIds": {
        "name": "portfolioIds",
        "in": "query",
        "required": false,
        "description": "Optional portfolio subset owned by the authenticated API account.",
        "schema": {
          "type": "array",
          "maxItems": 100,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "format": "uuid"
          }
        }
      }
    }
  }
}
