# Glider V2 API - **OpenAPI Version:** `3.1.0` - **API Version:** `2.0.0` The Glider V2 API is a REST surface for integrator partners to create rebalance strategies, enroll end-users into them, and monitor or withdraw the resulting portfolios. **Mental model.** A *strategy* is a reusable template (allocation + schedule + swap preferences). A *portfolio* is one end-user's mirror of a strategy with one smart account per chain. Every portfolio enrolled in a strategy mirrors the same allocation; publishing a new strategy version causes enrolled portfolios to re-target on their next scheduled rebalance. **Rebalances.** Each portfolio runs on the strategy's schedule (`hourly`/`daily`/`weekly`/`monthly`). Integrators can also dispatch an out-of-band run with `POST /v2/portfolios/{id}/rebalance` — useful when an end-user wants to capture or hedge market volatility without waiting for the next tick. Runtime visibility (`nextDueAt`, `lastRebalanceAt`) lives on `GET /v2/portfolios/{id}` under `schedule`, not on the strategy. **Asset coverage.** Allocations accept any CAIP-19 asset Glider supports — ERC-20 tokens, SPL tokens, and tokenized real-world assets (equities, treasuries) sourced through Glider's upstream data providers. Token metadata, balances, and USD prices are returned uniformly via `GET /v2/portfolios/{id}/positions`. **Chain abstraction.** Glider's wallet infrastructure handles cross-chain deposit routing and asset migrations between supported chains. Integrators do not need to plan for client-side migrations when a chain is sunset or a strategy moves liquidity venues. **Conventions.** Authentication uses API keys (`x-api-key` header) with per-scope access. All identifiers are CAIP-10/CAIP-19 so the same shape works across EVM and non-EVM chains. All monetary values are decimal strings — never numbers — to preserve precision across JSON round-trips. **Terms.** Use of this API is governed by Glider's B2B API terms (see `termsOfService`). Integrators are responsible for surfacing applicable terms to their own end-users. ## Servers - **URL:** `https://api.glider.fi/v2` - **Description:** Production ## Operations ### List available scopes - **Method:** `GET` - **Path:** `/scopes` - **Tags:** Discovery Returns every scope defined in the system with its description and granting tier. No authentication required. #### Responses ##### Status: 200 Available scopes ###### Content-Type: application/json - **`data` (required)** `object` - **`scopes` (required)** `array` **Items:** - **`description` (required)** `string` — Human-readable description - **`name` (required)** `string`, possible values: `"strategies:read", "strategies:write", "portfolios:read", "portfolios:write", "portfolios:withdraw", "enroll:write", "tenant:read", "tenant:write", "fees:read", "fees:write"` — Canonical scope identifier (\`resource:action\`) - **`tier` (required)** `string`, possible values: `"default", "standard", "restricted"` — Granting tier: \`default\` (auto-granted), \`standard\` (self-service), \`restricted\` (admin-only) - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "scopes": [ { "name": "strategies:read", "description": "List and view strategies", "tier": "default" } ] } } ``` ### Current API key identity - **Method:** `GET` - **Path:** `/whoami` - **Tags:** Discovery Returns the identity and permissions of the current API key. Use this to verify your key works and see which scopes are granted. #### Responses ##### Status: 200 API key identity and permissions ###### Content-Type: application/json - **`data` (required)** `object` - **`apiKeyId` (required)** `string | null` — API key record ID. Null only for legacy keys that have not migrated to better-auth. - **`scopes` (required)** `array` — Granted scopes for this API key **Items:** `string`, possible values: `"strategies:read", "strategies:write", "portfolios:read", "portfolios:write", "portfolios:withdraw", "enroll:write", "tenant:read", "tenant:write", "fees:read", "fees:write"` — Canonical scope identifier (\`resource:action\`) - **`tenantEmail` (required)** `string` — Tenant contact email - **`tenantName` (required)** `string` — Display name of the tenant - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "tenantName": "Integrator", "tenantEmail": "dev@integrator.example", "apiKeyId": "key_01JWZEE2MF30KVRMRX53N88VA4", "scopes": [ "strategies:read", "portfolios:read" ] } } ``` ##### Status: 400 Bad request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Legacy key without tenant identity ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### List public, mirrorable strategies - **Method:** `GET` - **Path:** `/discovery/strategies` - **Tags:** Discovery Returns Glider's public + mirrorable strategies for the chosen `collection` — `curated` (a hand-picked set, in editorial order) or `top_performing` (analytics-ranked). Both are keyset-paginated: follow `nextCursor` to page through results, keeping `collection` stable across pages. For `top_performing` the cursor encodes its `sort`, so `sort` need not be re-sent (if sent, it must match). Requires a valid API key; no scope. #### Responses ##### Status: 200 Public, mirrorable strategies ###### Content-Type: application/json - **`data` (required)** `object` - **`strategies` (required)** `array` **Items:** - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`canMirror` (required)** `boolean`, possible values: `true` — Always true — only mirrorable strategies appear here. Use \`strategyId\` with the enroll flow to mirror. - **`createdAt` (required)** `string | null` — ISO 8601 creation timestamp of the strategy. Null when unknown. - **`description` (required)** `string | null` — Strategy description. Null when none was provided. - **`metrics` (required)** `object` - **`performance` (required)** `object` - **`summary` (required)** `object` — Target-allocation performance windows (1d…12m), same shape as \`GET /v2/strategies/{strategyId}/performance\`. \`windows\` is empty when price history is too short. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. - **`portfolioCount` (required)** `integer | null` — Number of portfolios created from this strategy. Null when the value is temporarily unavailable — never conflated with a real 0. - **`tvlUsd` (required)** `string | null` — Total value locked across the strategy's active portfolios, as a USD decimal string rounded to 2 decimal places. Null when the value is temporarily unavailable — never conflated with a real "0.00". - **`name` (required)** `string` — Display name for the strategy. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not a computed return. Absent when no APY is advertised. - **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategies": [ { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "createdAt": "2026-04-17T12:00:00.000Z", "metrics": { "tvlUsd": "1250342.18", "portfolioCount": 421, "performance": { "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } }, "canMirror": true } ] }, "nextCursor": null } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Validate a create-strategy request without persisting - **Method:** `POST` - **Path:** `/strategies/validate` - **Tags:** Strategies Runs the same validation gates as `POST /v2/strategies` without persisting anything. Useful for pre-flight checks before submitting a create request. Returns 200 on success or 400 with the same error shape the create endpoint would return. #### Request Body ##### Content-Type: application/json - **`allocation` (required)** `object` - **`name` (required)** `string` — Display name for the strategy - **`schedule` (required)** `object` — Rebalance schedule — when to rebalance. - **`description`** `string | null`, default: `null` — Optional description of the strategy - **`isPublic`** `boolean`, default: `false` — Whether the strategy is publicly discoverable - **`preferences`** `object` — Optional swap execution constraints. System defaults apply if omitted. - **`swap` (required)** `object` - **`priceImpactBps`** `integer` — Max price impact in basis points (0–1000). Omit to use the system default. - **`slippageBps`** `integer` — Max slippage in basis points (0–1000). Omit to use the system default. - **`thresholdUsd`** `string` — Minimum swap size in USD as a decimal string (>= 1.00). Omit to use the system default. **Example:** ```json { "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "allocation": null, "schedule": { "type": "interval", "frequency": "daily" }, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false } ``` #### Responses ##### Status: 200 Strategy input is valid ###### Content-Type: application/json - **`data` (required)** `object` - **`valid` (required)** `boolean`, possible values: `true` — Always \`true\` on a 2xx response. Validation failures return 400 with the same error shape the create endpoint would return. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "valid": true } } ``` ##### Status: 400 Invalid request, asset blocklisted, or allocation validation failed ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Create a strategy - **Method:** `POST` - **Path:** `/strategies` - **Tags:** Strategies Creates a new strategy with an initial allocation version. Schedule and optional swap preferences are stored alongside the strategy. Returns the created strategy with a ULID-based strategyId. #### Request Body ##### Content-Type: application/json - **`allocation` (required)** `object` - **`name` (required)** `string` — Display name for the strategy - **`schedule` (required)** `object` — Rebalance schedule — when to rebalance. - **`description`** `string | null`, default: `null` — Optional description of the strategy - **`isPublic`** `boolean`, default: `false` — Whether the strategy is publicly discoverable - **`preferences`** `object` — Optional swap execution constraints. System defaults apply if omitted. - **`swap` (required)** `object` - **`priceImpactBps`** `integer` — Max price impact in basis points (0–1000). Omit to use the system default. - **`slippageBps`** `integer` — Max slippage in basis points (0–1000). Omit to use the system default. - **`thresholdUsd`** `string` — Minimum swap size in USD as a decimal string (>= 1.00). Omit to use the system default. **Example:** ```json { "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "allocation": null, "schedule": { "type": "interval", "frequency": "daily" }, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false } ``` #### Responses ##### Status: 201 Strategy created ###### Content-Type: application/json - **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ##### Status: 400 Invalid request or allocation validation failed ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### List strategies - **Method:** `GET` - **Path:** `/strategies` - **Tags:** Strategies Returns the authenticated tenant's strategies in `createdAt` descending order using cursor-based pagination. #### Responses ##### Status: 200 Tenant strategies ###### Content-Type: application/json - **`data` (required)** `object` - **`strategies` (required)** `array` **Items:** - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. - **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategies": [ { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } ] }, "nextCursor": null } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get strategy-specific preference overrides - **Method:** `GET` - **Path:** `/strategies/{strategyId}/preferences` - **Tags:** Strategies Returns the strategy's stored preference overrides. Swap settings live under the `swap` namespace: `slippageBps`, `priceImpactBps`, `thresholdUsd`. Each inner field is `null` when no override is set. The strategy's schedule is read via `GET /v2/strategies/{strategyId}/schedule`. Public strategies from discovery are also readable and return the creator's overrides (only the owner can change them). Anything else returns 404. #### Responses ##### Status: 200 Strategy-specific preference override view ###### Content-Type: application/json - **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Patch strategy-specific preference overrides - **Method:** `PATCH` - **Path:** `/strategies/{strategyId}/preferences` - **Tags:** Strategies Patches the strategy's stored preference overrides. Swap settings live under the `swap` namespace: `slippageBps`, `priceImpactBps`, `thresholdUsd`. JSON Merge Patch semantics (RFC 7396) at the inner-field level: omit to preserve, send `null` to clear, send a value to set. Empty bodies `{}` and `{ "swap": {} }` are both 200 no-ops. The schedule is changed via `PUT /v2/strategies/{strategyId}/schedule` — sending a `schedule` field here returns 400. Cross-tenant access returns 404. #### Request Body ##### Content-Type: application/json - **`swap`** `object` - **`priceImpactBps`** `integer | null` — Max price impact in basis points (0–1000). Pass \`null\` to clear; omit to preserve. - **`slippageBps`** `integer | null` — Max slippage in basis points (0–1000). Pass \`null\` to clear; omit to preserve. - **`thresholdUsd`** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Pass \`null\` to clear; omit to preserve. **Example:** ```json { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } ``` #### Responses ##### Status: 200 Strategy-specific preference override view after the patch ###### Content-Type: application/json - **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ##### Status: 400 Invalid patch body ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get strategy-specific integrator-fee override - **Method:** `GET` - **Path:** `/strategies/{strategyId}/fees` - **Tags:** Strategies Returns the strategy's stored integrator-fee override. `swapBps` is `null` when no per-strategy override is configured. Cross-tenant access returns 404. #### Responses ##### Status: 200 Strategy-specific fee override view ###### Content-Type: application/json - **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Patch strategy-specific integrator-fee override - **Method:** `PATCH` - **Path:** `/strategies/{strategyId}/fees` - **Tags:** Strategies Patches the strategy's integrator-fee override. JSON Merge Patch semantics (RFC 7396): omit to preserve, send `null` to clear the per-strategy override, send a value to set. Empty body `{}` is a 200 no-op. Cross-tenant access returns 404. #### Request Body ##### Content-Type: application/json - **`swapBps`** `integer | null` — Integrator swap fee in basis points (30–300). Pass \`null\` to clear; omit to preserve. **Example:** ```json { "swapBps": 50 } ``` #### Responses ##### Status: 200 Strategy-specific fee override view after the patch ###### Content-Type: application/json - **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ##### Status: 400 Invalid patch body ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get the strategy's rebalance schedule - **Method:** `GET` - **Path:** `/strategies/{strategyId}/schedule` - **Tags:** Strategies Returns the strategy's *configured* rebalance cadence (`type` + `frequency`). Schedule is set at strategy creation and updated via `PUT /v2/strategies/{strategyId}/schedule`. This endpoint does not return runtime state — for `nextDueAt`, `lastRebalanceAt`, and `status` (active/paused) per portfolio, read the `schedule` block on `GET /v2/portfolios/{portfolioId}`. Public strategies from discovery are also readable and return the creator's cadence, or `null` when they have none configured. Anything else returns 404. #### Responses ##### Status: 200 Strategy rebalance schedule ###### Content-Type: application/json - **`data` (required)** `object` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "type": "interval", "frequency": "daily" } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Change a strategy's rebalance cadence (fans out to enrolled portfolios) - **Method:** `PUT` - **Path:** `/strategies/{strategyId}/schedule` - **Tags:** Strategies Sets the strategy's rebalance schedule. The new cadence takes effect on the next rebalance cycle for every enrolled portfolio of this strategy, including paused portfolios — they will run on the new cadence the moment they resume. Cross-tenant access returns 404. **Scope warning:** `strategies:write` carries a fleet-wide side effect on this route — do not grant it to keys exposed to runtime/end-user surfaces. #### Request Body ##### Content-Type: application/json **Any of:** - **`frequency` (required)** `string`, possible values: `"hourly", "daily", "weekly", "monthly"` — Rebalance cadence - **`type` (required)** `string`, possible values: `"interval"` — Fixed rebalance cadence using a supported frequency enum. * **`cron` (required)** `string` — Five-field cron expression. * **`timezone` (required)** `string` — IANA timezone used to interpret the cron expression. * **`type` (required)** `string`, possible values: `"cron"` — Cron-backed rebalance cadence. **Example:** ```json { "type": "interval", "frequency": "daily" } ``` #### Responses ##### Status: 200 Strategy rebalance schedule after the change + fan-out ###### Content-Type: application/json - **`data` (required)** `object` — Rebalance schedule — when to rebalance. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "type": "interval", "frequency": "daily" } } ``` ##### Status: 400 Invalid schedule body ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get strategy performance - **Method:** `GET` - **Path:** `/strategies/{strategyId}/performance` - **Tags:** Strategies Returns the strategy's target-allocation time-weighted performance curve over the shorter of 12 months or the shared asset price history window. Your own strategies use their configured rebalance schedule; public strategies from discovery (curated or top-performing) are also readable and use the creator's rebalance cadence when available, defaulting to a daily rebalance assumption. Anything else returns 404. #### Responses ##### Status: 200 Strategy performance curve ###### Content-Type: application/json - **`data` (required)** `object` - **`meta` (required)** `object` - **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. - **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. - **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. - **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. - **`points` (required)** `array` — Daily chart points for the strategy performance curve. **Items:** - **`date` (required)** `string` — UTC calendar date for this point. - **`percentChange` (required)** `string` — Cumulative return at this point under the response's \`meta.method\`. \`TWR\` is compounded from the first returned point; \`MWR\` is the money-weighted return, which reflects deposits and withdrawals. - **`schedule` (required)** `object` — Rebalance schedule — when to rebalance. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`summary`** `object` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "schedule": { "type": "interval", "frequency": "daily" }, "meta": { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" }, "points": [ { "date": "2026-04-30", "percentChange": "4.1234" } ], "summary": null } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### List strategy versions - **Method:** `GET` - **Path:** `/strategies/{strategyId}/versions` - **Tags:** Strategies Returns the strategy's allocation version history, newest first. Cursor-paginated. The `isHead` flag identifies the active version. Public strategies from discovery (curated or top-performing) are also readable. Anything else returns 404. #### Responses ##### Status: 200 Strategy version history ###### Content-Type: application/json - **`data` (required)** `object` - **`versions` (required)** `array` **Items:** - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`changeLog` (required)** `string | null` — Optional note from the publish call. \`null\` when not provided. - **`createdAt` (required)** `string` — ISO 8601 timestamp when this version was published. - **`isHead` (required)** `boolean` — True for the active version. Exactly one per strategy. - **`version` (required)** `integer` — Sequential version number, server-assigned. v1 at create; each publish increments by 1. - **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "versions": [ { "version": 3, "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "changeLog": "Increased USDC weight from 60% to 70%", "isHead": true, "createdAt": "2026-04-17T12:00:00.000Z" } ] }, "nextCursor": null } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Publish a new strategy version - **Method:** `POST` - **Path:** `/strategies/{strategyId}/versions` - **Tags:** Strategies Publishes a new allocation version and makes it the active one. **Affects every enrolled portfolio:** the new allocation is what every portfolio will rebalance to on its next scheduled run. Pause portfolios via `POST /v2/portfolios/{portfolioId}/stop` first if you need a staged rollout. Concurrent publishes serialize per strategy and produce sequential version numbers; the last one becomes the active version. Cross-tenant access returns 404. #### Request Body ##### Content-Type: application/json - **`allocation` (required)** `object` - **`changeLog`** `string | null` — Optional note (≤500 chars) shown in the version history. Two publishes with identical allocations but different notes are both accepted. **Example:** ```json { "allocation": null, "changeLog": "Increased USDC weight from 60% to 70%" } ``` #### Responses ##### Status: 201 Version published; this is now the active version ###### Content-Type: application/json - **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`changeLog` (required)** `string | null` — Optional note from the publish call. \`null\` when not provided. - **`createdAt` (required)** `string` — ISO 8601 timestamp when this version was published. - **`isHead` (required)** `boolean` — True for the active version. Exactly one per strategy. - **`version` (required)** `integer` — Sequential version number, server-assigned. v1 at create; each publish increments by 1. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "version": 3, "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "changeLog": "Increased USDC weight from 60% to 70%", "isHead": true, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ##### Status: 400 Invalid request or allocation validation failed ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get strategy detail - **Method:** `GET` - **Path:** `/strategies/{strategyId}` - **Tags:** Strategies Returns strategy detail. Your own strategies return their full execution config. Public strategies from discovery (curated or top-performing) are also readable: `schedule` and `preferences` are the creator's (schedule is null when they have none configured; preference fields are null when unset). Anything else returns 404 — no existence leak. #### Responses ##### Status: 200 Strategy detail ###### Content-Type: application/json - **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` — Rebalance schedule. Always populated for your own strategies (required at creation). Null only when reading a public strategy from another tenant whose creator has no schedule configured. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": { "type": "interval", "frequency": "daily" }, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Patch strategy metadata - **Method:** `PATCH` - **Path:** `/strategies/{strategyId}` - **Tags:** Strategies Patches the strategy's display metadata: `name`, `description`, `isPublic`. JSON Merge Patch (RFC 7396): omit to preserve, `null` to clear (nullable fields only), value to set. Empty body `{}` is a 200 no-op. Body is strict; unknown keys return 400. Allocation goes through `POST /v2/strategies/{strategyId}/versions`. Cross-tenant access returns 404. #### Request Body ##### Content-Type: application/json - **`description`** `string | null` — Integrator-provided description. Send \`null\` to clear. - **`isPublic`** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name`** `string` — Display name for the strategy. Cannot be cleared. **Example:** ```json { "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "isPublic": false } ``` #### Responses ##### Status: 200 Patched strategy detail ###### Content-Type: application/json - **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ##### Status: 400 Invalid patch body ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get tenant-wide preference defaults - **Method:** `GET` - **Path:** `/tenant/preferences` - **Tags:** Tenant Returns the tenant's stored preference defaults. Swap settings live under the `swap` namespace: slippage (`slippageBps`), price impact (`priceImpactBps`), and minimum swap size (`thresholdUsd`). Each inner field is `null` when not configured. Schedule is per-strategy — see `GET /v2/strategies/{strategyId}/schedule`. #### Responses ##### Status: 200 Tenant preferences view ###### Content-Type: application/json - **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Patch tenant-wide preference defaults - **Method:** `PATCH` - **Path:** `/tenant/preferences` - **Tags:** Tenant Patches the tenant's stored preference defaults. Swap settings live under the `swap` namespace: `slippageBps`, `priceImpactBps`, `thresholdUsd`. JSON Merge Patch semantics (RFC 7396) at the inner-field level: omit to preserve, send `null` to clear, send a value to set. Empty bodies `{}` and `{ "swap": {} }` are both 200 no-ops. Schedule is per-strategy — see `PUT /v2/strategies/{strategyId}/schedule`. #### Request Body ##### Content-Type: application/json - **`swap`** `object` - **`priceImpactBps`** `integer | null` — Max price impact in basis points (0–1000). Pass \`null\` to clear; omit to preserve. - **`slippageBps`** `integer | null` — Max slippage in basis points (0–1000). Pass \`null\` to clear; omit to preserve. - **`thresholdUsd`** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Pass \`null\` to clear; omit to preserve. **Example:** ```json { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } ``` #### Responses ##### Status: 200 Merged tenant preferences view after the patch ###### Content-Type: application/json - **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ##### Status: 400 Invalid patch body ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get tenant-wide integrator fee defaults - **Method:** `GET` - **Path:** `/tenant/fees` - **Tags:** Tenant Returns the tenant's stored integrator-fee defaults. `swapBps` is the basis-point fee charged on the output side of every swap; `null` when not configured. Per-strategy overrides live at `GET /v2/strategies/{strategyId}/fees`. #### Responses ##### Status: 200 Tenant fees view ###### Content-Type: application/json - **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Patch tenant-wide integrator fee defaults - **Method:** `PATCH` - **Path:** `/tenant/fees` - **Tags:** Tenant Patches the tenant's stored integrator-fee defaults. JSON Merge Patch semantics (RFC 7396) at the inner-field level: omit to preserve, send `null` to clear, send a value to set. Empty body `{}` is a 200 no-op. Per-strategy overrides go to `PATCH /v2/strategies/{strategyId}/fees`. #### Request Body ##### Content-Type: application/json - **`swapBps`** `integer | null` — Integrator swap fee in basis points (30–300). Pass \`null\` to clear; omit to preserve. **Example:** ```json { "swapBps": 50 } ``` #### Responses ##### Status: 200 Merged tenant fees view after the patch ###### Content-Type: application/json - **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ##### Status: 400 Invalid patch body ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get the signable message for enrolling a user - **Method:** `POST` - **Path:** `/enroll/signature` - **Tags:** Enrollment Stage 1 of the two-stage enroll flow. Validates that the `strategyId` belongs to the calling tenant, reserves an on-chain account index, resolves or allocates a pooled KMS agent for the user, and returns the session-key message the user must sign in their wallet. The response's `flowId`, `accountIndex`, and `agentAccountId` must all be passed back verbatim to `POST /v2/enroll`. #### Request Body ##### Content-Type: application/json - **`chainIds` (required)** `array` — Numeric chain ids the user wants smart accounts on. Must be a subset of the chains this deployment has RPCs configured for. **Items:** `integer` - **`ownerAccountId` (required)** `string` — End-user wallet as a CAIP-10 identifier. EVM: \`eip155:0:\\` (chain-agnostic per CAIP-10 §Abstract Account Addresses). Solana: \`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\` (CAIP-2 mainnet reference). - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`accountType`** `string`, possible values: `"ECDSA", "ERC1271"`, default: `"ECDSA"` — EVM Kernel owner/validator configuration. \`ECDSA\` uses the MultiChainECDSAValidator. \`ERC1271\` uses the Kernel SmartAccount validator and requires exactly one EVM chainId. **Example:** ```json { "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "chainIds": [ 1, 8453 ], "accountType": "ECDSA" } ``` #### Responses ##### Status: 200 Signable message issued ###### Content-Type: application/json - **`data` (required)** `object` - **`accountIndex` (required)** `string` — Reserved account index. Must be round-tripped to \`POST /v2/enroll\`. - **`agentAccountId` (required)** `string` — Pooled KMS agent as a chain-agnostic CAIP-10 identifier (\`eip155:0:\\`) that will operate the smart account post-enrollment. Must be round-tripped verbatim to \`POST /v2/enroll\`. - **`flowId` (required)** `string` — Opaque 24h reservation token. Must be round-tripped to \`POST /v2/enroll\` and also serves as the idempotency anchor there. - **`message` (required)** `object` — Discriminated union. ECDSA enrollment returns \`{ kind: "ecdsa", raw }\`; ERC-1271 enrollment returns \`{ kind: "typed-data", typedData }\`; SVM enrollment may return \`{ kind: "solana-message", text }\`. - **`accountType`** `string`, possible values: `"ECDSA", "ERC1271"` — EVM Kernel owner/validator configuration used to build \`message\`. Round-trip this to \`POST /v2/enroll\` when present. - **`depositAccountId`** `string` — SVM B2B subaccount path only: CAIP-10 of the Swig sub-account the user will deposit funds to once enrolled. Mirrors what \`POST /v2/enroll\` returns in \`smartAccounts\[].depositAccountId\`. - **`reusedSwig`** `boolean` — SVM B2B subaccount path only: \`true\` when an existing Swig PDA for this (tenant, user) is being reused (a subsequent vault), \`false\` when a new one will be created (the first vault). - **`solanaTransaction`** `string` — SVM B2B subaccount path only: the base64-serialized Solana transaction the user signs with their wallet (it creates — or reuses — the deterministic Swig and adds a sub-account). Sign this and round-trip the signed bytes to \`POST /v2/enroll\` as \`signedSolanaTransaction\`, instead of signing \`message\`. Carries a recent blockhash, so sign and submit promptly. - **`swigAccountId`** `string` — SVM B2B Model A (EVM-rooted) subaccount only: CAIP-10 of the parent Swig. The client needs it (plus \`agentAccountId\` and a fresh slot) to build the add-authority message the user signs with their EVM wallet, then submits to \`POST /v2/enroll\` with \`userSecp256k1PublicKey\` + \`currentSlot\`. - **`swigRoleId`** `integer` — SVM B2B subaccount path only: the Swig role id that will own the sub-account. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "message": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }, "agentAccountId": "eip155:0:0x1111111111111111111111111111111111111111", "accountIndex": "7", "accountType": "ECDSA", "flowId": "flow_01JWZEE2MF30KVRMRX53N88VA4", "solanaTransaction": "", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1, "reusedSwig": true, "swigAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj" } } ``` ##### Status: 400 Invalid request or unknown strategy ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Create a portfolio for an enrolled user - **Method:** `POST` - **Path:** `/enroll` - **Tags:** Enrollment Stage 2 of the two-stage enroll flow. Consumes the `flowId` + `accountIndex` + `agentAccountId` returned by `POST /v2/enroll/signature` plus the user's `signature` over the session-key message. Verifies the signature, creates the mirror strategy instance, one smart account per chain, and a rebalance schedule row derived from the strategy's execution config — all inside a single transaction. The whole operation is idempotent on `(tenantId, apiKeyId, "POST /v2/enroll", flowId)` via the `v2_idempotency_keys` store; a replay with the same body returns the cached response, a replay with a different body returns 409. #### Request Body ##### Content-Type: application/json - **`accountIndex` (required)** `string` — Reserved account index as a decimal string. Must round-trip from \`POST /v2/enroll/signature\` into \`POST /v2/enroll\` so the server can recompute the session-key message. - **`agentAccountId` (required)** `string` — Pooled KMS agent CAIP-10 returned by \`POST /v2/enroll/signature\`. Must round-trip verbatim so the server can recompute the signable message. EVM (\`eip155:0:\\`) or Solana (\`solana:\:\\`). - **`chainIds` (required)** `array` — Numeric chain ids the user wants smart accounts on. Must be a subset of the chains this deployment has RPCs configured for. **Items:** `integer` - **`flowId` (required)** `string` — Opaque flow identifier. Valid for 24h. Also the idempotency anchor for \`POST /v2/enroll\`. - **`ownerAccountId` (required)** `string` — End-user wallet as a CAIP-10 identifier. EVM: \`eip155:0:\\`. Solana: \`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\`. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`accountType`** `string`, possible values: `"ECDSA", "ERC1271"`, default: `"ECDSA"` — EVM Kernel owner/validator configuration. Must match the value used for \`POST /v2/enroll/signature\`. \`ERC1271\` requires exactly one EVM chainId. - **`currentSlot`** `string` — SVM B2B Model A subaccount: the Solana slot the client captured and bound \`signature\` to (decimal string). Submit promptly — Swig enforces a slot window. - **`ownerSignatureScheme`** `string`, possible values: `"eip191", "raw"` — SVM B2B Model A subaccount: how the wallet produced \`signature\` over the Swig payload hash. \`eip191\` (default) = \`personal\_sign\`; \`raw\` = bare secp256k1 over the hash. - **`portfolioName`** `string` — Integrator-provided display name for the portfolio. Trimmed server-side. Max 64 characters. Supports Unicode letters, digits, spaces, and - \_ . ' : ( ) & /. - **`signature`** `string` — Signature over the stage-1 message. Hex (EVM ECDSA / SVM Model A) or base58. Required for every path EXCEPT the SVM B2B subaccount path, which instead returns \`signedSolanaTransaction\`. - **`signedSolanaTransaction`** `string` — SVM B2B only: the base64-serialized, user-signed Solana transaction from \`POST /v2/enroll/signature\` (\`solanaTransaction\`). Provide this instead of \`signature\` for the SVM Model B subaccount enroll path. - **`userSecp256k1PublicKey`** `string` — SVM B2B Model A (EVM-rooted) subaccount: the user's secp256k1 public key (\`0x…\` hex). Required for the Model A subaccount path; its derived address must equal \`ownerAccountId\`'s address. Sent alongside \`signature\` (the slot-bound Swig authorization) and \`currentSlot\`. **Example:** ```json { "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "chainIds": [ 1, 8453 ], "accountType": "ECDSA", "accountIndex": "7", "agentAccountId": "eip155:0:0x1111111111111111111111111111111111111111", "signature": "0x9412d70d539f889ecec2d3152b68af758d689a4325a43b07811ee708814527c72256fc749d7fd3745a07f0aaa84813955050c461392d9b9ee1f80e106fac39e01b", "signedSolanaTransaction": "", "userSecp256k1PublicKey": "", "currentSlot": "299999999", "ownerSignatureScheme": "eip191", "flowId": "flow_01JWZEE2MF30KVRMRX53N88VA4", "portfolioName": "Alice's Portfolio" } ``` #### Responses ##### Status: 201 Portfolio enrolled ###### Content-Type: application/json - **`data` (required)** `object` - **`portfolioId` (required)** `string` — Portfolio identifier - **`portfolioName` (required)** `string | null` — Integrator-provided display name for the portfolio. Null when the portfolio was created without one. - **`smartAccounts` (required)** `array` — Canonical SmartAccount objects, one per requested chain. Deterministic CREATE2 addresses. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ] } } ``` ##### Status: 400 Invalid request, unknown strategy, expired flow, or invalid signature ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 409 Idempotency replay-in-progress, key-conflict, or user already enrolled ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### List portfolios - **Method:** `GET` - **Path:** `/portfolios` - **Tags:** Portfolios Returns the authenticated tenant's portfolios with optional filtering by `ownerAccountId`, `strategyId`, and `status`. Live balances and positions are served by `GET /v2/portfolios/{portfolioId}/positions`. Cursor-paginated, most recently created first; use the opaque `nextCursor` to fetch the next page. #### Responses ##### Status: 200 Tenant portfolios ###### Content-Type: application/json - **`data` (required)** `object` - **`portfolios` (required)** `array` **Items:** - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`ownerAccountId` (required)** `string | null` — End-user wallet as a chain-agnostic CAIP-10 identifier (\`eip155:0:\\`). Null only for legacy rows without an owner recorded. - **`portfolioId` (required)** `string` — Portfolio identifier - **`portfolioName` (required)** `string | null` — Integrator-provided display name for the portfolio. Null when the portfolio was created without one. - **`schedule` (required)** `object | null` — Rebalance schedule projection. Null when no rebalance schedule has been created for this portfolio. - **`frequency` (required)** `string | null`, possible values: `"hourly", "daily", "weekly", "monthly", null` — Resolved cadence enum. Null when the stored spec uses a non-standard \`intervalMs\` that does not map to the enum. - **`intervalMs` (required)** `integer | null` — Raw interval between rebalances in milliseconds - **`lastRebalanceAt` (required)** `string | null` — ISO 8601 timestamp for the most recent rebalance run (manual or scheduled). Null until the portfolio's first rebalance completes. - **`nextDueAt` (required)** `string | null` — ISO 8601 timestamp for the next scheduled rebalance. Use this to render 'next rebalance in …' UI or to decide whether to trigger a manual rebalance now. Null when the schedule is paused or no next tick has been computed yet. - **`status` (required)** `string`, possible values: `"active", "paused"` — Portfolio rebalance schedule status. \`active\` = scheduler will tick. \`paused\` = integrator has paused automation. - **`smartAccounts` (required)** `array` — Per-chain smart accounts owned by this portfolio. Each entry is the canonical \`SmartAccount\` object. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. - **`strategyDescription` (required)** `string | null` — Strategy description as set by the integrator at strategy creation time. Null when the strategy was created without one. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`strategyName` (required)** `string` — Strategy display name at read time - **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolios": [ { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z" } ] }, "nextCursor": null } ``` ##### Status: 400 Invalid request (bad cursor, filters, or pagination params) ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get portfolio live positions - **Method:** `GET` - **Path:** `/portfolios/{portfolioId}/positions` - **Tags:** Portfolios Returns real-time per-asset balances and USD values for a portfolio. The `assets[]` array spans every asset class the underlying allocation supports — ERC-20 tokens, SPL tokens, and tokenized real-world assets (equities, treasuries) — using one uniform shape (`assetId`, `symbol`, `decimals`, `balance`, `balanceRaw`, `priceUsd`, `valueUsd`). Token metadata and prices are sourced from Glider's upstream data providers and passed through unchanged. Results may be cached for up to 30 seconds. Partial failures are surfaced in `warnings[]` and do not fail the request — the endpoint returns 200 with whatever loaded. For schedule/status polling (including `nextDueAt` and `lastRebalanceAt`) without live balances, use `GET /v2/portfolios/{portfolioId}` instead. #### Responses ##### Status: 200 Portfolio live positions ###### Content-Type: application/json - **`data` (required)** `object` - **`assets` (required)** `array` **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier (fully chain-qualified). Covers ERC-20, SPL, and tokenized RWA assets — the same shape regardless of asset class. - **`balance` (required)** `string` — Human-readable token balance as a decimal string - **`balanceRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. - **`decimals` (required)** `integer` — Integer exponent used to convert \`balanceRaw\` to \`balance\`. The only non-string financial field on the v2 surface. - **`priceUsd` (required)** `string` — Unit price in USD as a decimal string, \`.toFixed(6)\` - **`smartAccountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`symbol` (required)** `string` — Asset symbol as reported by the upstream data provider (e.g. \`USDC\`, \`MORPHO\`, or a tokenized-equity ticker). - **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`fetchedAt` (required)** `string` — ISO 8601 timestamp at which balances + prices were read - **`inTransit` (required)** `object` — Open bridge value included in totalValueUsd but not yet visible as settled destination-chain asset rows. - **`items` (required)** `array` — Open bridge legs included in totalValueUsd but not yet reflected as destination-chain asset rows. **Items:** - **`amountRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. - **`destinationChainId` (required)** `integer` — Destination EVM chain id for the bridge leg. - **`sourceAssetId` (required)** `string` — Source asset identifier used for the in-transit bridge leg. This matches the source asset id used internally for the portfolio position. - **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`totalUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`portfolioId` (required)** `string` — Portfolio identifier - **`smartAccounts` (required)** `array` — Smart accounts configured for this portfolio. Always present regardless of whether live balances loaded. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. - **`totalValueUsd` (required)** `string` — Total USD value as a decimal string, \`.toFixed(6)\`. Sum of asset \`valueUsd\` for a single portfolio. - **`warnings` (required)** `array` — Non-fatal issues encountered while loading positions (e.g. a chain was unavailable, a price was missing). Empty array means a fully-healthy read. **Items:** - **`kind` (required)** `string`, possible values: `"MISSING_SMART_ACCOUNT", "RPC_ERROR", "MISSING_PRICE", "BLOCKLISTED_ASSET", "MISSING_ASSET", "IN_TRANSIT_READ_FAILED"` — Warning kind - **`message` (required)** `string` — Human-readable detail - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "totalValueUsd": "1500.500000", "inTransit": { "totalUsd": "1500.500000", "items": [ { "sourceAssetId": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913:8453", "destinationChainId": 42161, "amountRaw": "1500500000", "valueUsd": "1500.500000" } ] }, "fetchedAt": "2026-04-17T12:05:10.000Z", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "assets": [ { "assetId": "eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "smartAccountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "symbol": "USDC", "decimals": 6, "balance": "1500.500000", "balanceRaw": "1500500000", "priceUsd": "1.000000", "valueUsd": "1500.500000" } ], "warnings": [ { "kind": "RPC_ERROR", "message": "chain 1 RPC timeout" } ] } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error or live balance service unavailable ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get portfolio equity sector exposure - **Method:** `GET` - **Path:** `/portfolios/{portfolioId}/sector-exposure` - **Tags:** Portfolios Returns current eligible equity exposure grouped by Glider's canonical sector classification. Tokenized equity positions are resolved to their canonical underlying through issuer-product routes or direct token-subject links. Unsupported non-equity positions are excluded from the denominator and returned in diagnostics. #### Responses ##### Status: 200 Portfolio equity sector exposure ###### Content-Type: application/json - **`data` (required)** `object` - **`asOfDate` (required)** `string` — ISO 8601 timestamp (UTC) - **`classifiedMarketValueUsd` (required)** `string` - **`diagnostics` (required)** `object` - **`lowConfidencePositions` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string` - **`assetId` (required)** `string` - **`confidence` (required)** `integer` - **`displaySector` (required)** `string`, possible values: `"Technology", "Communication Services", "Consumer Cyclical", "Consumer Defensive", "Financial Services", "Healthcare", "Industrials", "Basic Materials", "Energy", "Utilities", "Real Estate", "Unclassified"` - **`marketValueUsd` (required)** `string` - **`source` (required)** `string`, possible values: `"manual_override", "financedatabase_share_class_figi", "financedatabase_composite_figi", "financedatabase_isin", "financedatabase_cusip", "financedatabase_cik", "financedatabase_symbol_exchange", "massive_sic_ff48", "massive_sic_direct", "unclassified"` - **`symbol` (required)** `string | null` - **`unclassifiedPositions` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`assetId` (required)** `string` - **`marketValueUsd` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`unsupportedPositions` (required)** `array` **Items:** - **`assetId` (required)** `string` - **`marketValueUsd` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`portfolioId` (required)** `string` — Portfolio identifier - **`rows` (required)** `array` **Items:** - **`classifiedPositionCount` (required)** `integer` - **`displaySector` (required)** `string`, possible values: `"Technology", "Communication Services", "Consumer Cyclical", "Consumer Defensive", "Financial Services", "Healthcare", "Industrials", "Basic Materials", "Energy", "Utilities", "Real Estate", "Unclassified"` - **`marketValueUsd` (required)** `string` - **`primarySources` (required)** `array` **Items:** - **`count` (required)** `integer` - **`marketValueUsd` (required)** `string` - **`source` (required)** `string`, possible values: `"manual_override", "financedatabase_share_class_figi", "financedatabase_composite_figi", "financedatabase_isin", "financedatabase_cusip", "financedatabase_cik", "financedatabase_symbol_exchange", "massive_sic_ff48", "massive_sic_direct", "unclassified"` - **`totalPositionCount` (required)** `integer` - **`weight` (required)** `string` - **`taxonomy` (required)** `string`, possible values: `"internal_display_sector_v1"` - **`totalMarketValueUsd` (required)** `string` - **`unclassifiedMarketValueUsd` (required)** `string` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "asOfDate": "2026-04-17T12:00:00.000Z", "taxonomy": "internal_display_sector_v1", "totalMarketValueUsd": "", "classifiedMarketValueUsd": "", "unclassifiedMarketValueUsd": "", "rows": [ { "displaySector": "Technology", "marketValueUsd": "", "weight": "", "classifiedPositionCount": 0, "totalPositionCount": 0, "primarySources": [ { "source": "manual_override", "count": 0, "marketValueUsd": "" } ] } ], "diagnostics": { "unsupportedPositions": [ { "assetId": "", "symbol": null, "reason": "", "marketValueUsd": "" } ], "unclassifiedPositions": [ { "assetId": "", "symbol": null, "assetCanonicalId": null, "reason": "", "marketValueUsd": "" } ], "lowConfidencePositions": [ { "assetId": "", "symbol": null, "assetCanonicalId": "", "displaySector": "Technology", "source": "manual_override", "confidence": 0, "marketValueUsd": "" } ] } } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error or live balance service unavailable ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get portfolio performance - **Method:** `GET` - **Path:** `/portfolios/{portfolioId}/performance` - **Tags:** Portfolios Returns the portfolio's daily performance curve. Defaults to money-weighted return (MWR), which reflects the user's actual money outcome. Pass returnMethod=TWR for strategy-style time-weighted return. Cross-tenant access returns 404. #### Responses ##### Status: 200 Portfolio performance curve ###### Content-Type: application/json - **`data` (required)** `object` - **`meta` (required)** `object` - **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. - **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. - **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. - **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. - **`points` (required)** `array` — Daily performance series for the portfolio using \`meta.method\`, with cash flows reported by UTC day. **Items:** - **`cashFlowUsd` (required)** `string` — Net external cash flow aggregated into this UTC day, denominated in USD. Signed: positive on net-deposit days, negative on net-withdrawal days, \`0\` when flows cancel or none occurred. - **`date` (required)** `string` — UTC calendar date for this point. - **`percentChange` (required)** `string | null` — Cumulative return at this point under \`meta.method\` (\`TWR\` compounded from the first returned point; \`MWR\` money-weighted, reflecting deposits and withdrawals). \`null\` when a return is unavailable for this point. - **`valueUsd` (required)** `string` — Portfolio value for this UTC day, denominated in USD. For today, this may reflect the latest live value. - **`isLive`** `boolean` — True when this daily point includes the latest live portfolio value. - **`portfolioId` (required)** `string` — Portfolio identifier - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`summary`** `object` — Aggregate stats derived from the points array. Omitted when the curve has fewer than two points. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "meta": { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" }, "points": [ { "date": "2026-04-30", "percentChange": "4.1234", "valueUsd": "1523.450000", "cashFlowUsd": "100.000000", "isLive": true } ], "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Start portfolio automation - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/start` - **Tags:** Portfolios Resumes the portfolio's rebalance schedule. Idempotent — starting an already-active portfolio returns its current state without side effects. On transition, `nextDueAt` is reset to the current timestamp so the next scheduler tick picks the portfolio up instead of honouring the stale due time that was captured when automation was stopped. #### Responses ##### Status: 200 Portfolio detail after transition ###### Content-Type: application/json - **`data` (required)** `object` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ##### Status: 400 Portfolio has no rebalance schedule ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Stop portfolio automation - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/stop` - **Tags:** Portfolios Pauses the portfolio's rebalance schedule. Idempotent — stopping an already-paused portfolio returns its current state without side effects. Rebalance history and all on-chain state are preserved; call `/start` to resume automation. #### Responses ##### Status: 200 Portfolio detail after transition ###### Content-Type: application/json - **`data` (required)** `object` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ##### Status: 400 Portfolio has no rebalance schedule ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Trigger a manual rebalance - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/rebalance` - **Tags:** Portfolios Dispatches a one-off rebalance for a portfolio your API key has access to, outside of the strategy's normal schedule. Typical use cases: an end-user wants to re-target immediately to capture or hedge market volatility, or your UI exposes a 'rebalance now' control. Returns immediately with an `operationId` that can be polled through the portfolio operations endpoint. A short cooldown is enforced between manual triggers per portfolio — see the `429` response and the `Retry-After` header for the wait window. #### Responses ##### Status: 202 Rebalance accepted and dispatched asynchronously ###### Content-Type: application/json - **`data` (required)** `object` - **`operationId` (required)** `string` — Operation identifier to poll with \`GET /v2/portfolios/{portfolioId}/operations/{operationId}\` for rebalance status. - **`submittedAt` (required)** `string` — ISO 8601 timestamp when the rebalance was accepted - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "operationId": "rebalance:a1b2c3d4:a1b2c3d4%3Amanual%3Areq_01JWZEE2MF30KVRMRX53N88VA4", "submittedAt": "2026-04-17T12:00:00.000Z" } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 429 Triggered too soon after the previous rebalance — see \`Retry-After\` ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Prepare a withdrawal authorization for user signing - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/withdraw/signature` - **Tags:** Portfolios Stage 1 of the two-stage withdraw flow. Stateless — the server validates the request, checks live onchain balances, generates a nonce + 10-minute expiry, and returns a signable authorization for the portfolio owner's wallet. EVM withdrawals receive an EIP-712 typed-data object under `data.typedData`; Solana withdrawals receive an off-chain authorization under `data.authorization` (`kind: "ecdsa"` — EVM-rooted Model A, signed via EIP-191; or `kind: "solana-message"` — Solana-rooted Model B, signed via ed25519). Stage 2 (`POST /v2/portfolios/{portfolioId}/withdraw`) accepts the inner `message` echoed back under `body.message` plus the user's signature and dispatches the onchain transfer. #### Request Body ##### Content-Type: application/json - **`assets` (required)** `array` — Assets to withdraw. All entries must be on the same chain as \`recipientAccountId\`. **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units as a decimal string. Read the live balance from \`GET /v2/portfolios/{portfolioId}/positions\` and echo \`balanceRaw\` for a full withdrawal. Must be a positive integer (no leading zeros). - **`assetId` (required)** `string` — CAIP-19 asset identifier. Chain is derived from the \`eip155:\\` prefix. - **`recipientAccountId` (required)** `string` — CAIP-10 recipient on the withdrawal chain. Every \`assets\[].assetId\` and, when \`liquidate\` is true, \`settlementAssetId\` must reference this same chain. Cross-chain delivery and bridging are not supported. EVM: \`eip155:\:\\`. Solana: \`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\`. One request authorizes one recipient on one chain; multi-chain withdrawals require separate authorizations. - **`liquidate`** `boolean`, default: `false` — When true, the listed \`assets\` are swapped to the \`settlementAssetId\` settlement asset (USDC by default) and delivered to \`recipientAccountId\`. Assets whose value is below the tenant swap threshold are skipped and stay in the vault. When false (default), each asset is transferred as-is. - **`settlementAssetId`** `string` — Liquidation only (\`liquidate: true\`). CAIP-19 settlement asset on the same chain as \`recipientAccountId\` and every \`assets\[].assetId\`. For an EVM withdrawal, use configured USDC or USDT on that EVM chain. For a Solana withdrawal, use Solana USDC. Omit to default to USDC on the withdrawal chain. This field does not select a different destination chain or enable bridging. Rejected when \`liquidate\` is false. **Example:** ```json { "recipientAccountId": "eip155:8453:0x4444444444444444444444444444444444444444", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "liquidate": false, "settlementAssetId": "eip155:56/erc20:0x55d398326f99059fF775485246999027B3197955" } ``` #### Responses ##### Status: 200 Authorization prepared; user must sign the returned typed data ###### Content-Type: application/json - **`data` (required)** `object` - **`authorizationId` (required)** `string` — Opaque 32-byte hex nonce. Use as the idempotency anchor for stage 2 retries of the same signed authorization. - **`expiresAt` (required)** `string` — ISO 8601 timestamp after which the authorization cannot be submitted. Matches the signed \`expiresAt\` (Unix seconds). - **`authorization`** `object` — Solana portfolios only. The off-chain authorization to sign with the portfolio owner's wallet — \`kind: "ecdsa"\` (EVM-rooted Model A; sign \`raw\` via EIP-191) or \`kind: "solana-message"\` (Solana-rooted Model B; sign \`text\` via ed25519). Echo \`authorization.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. - **`typedData`** `object` — EVM portfolios only. Full EIP-712 typed-data object. Pass directly to \`signTypedData(...)\` in the user's wallet; echo \`typedData.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. - **`domain` (required)** `object` - **`chainId` (required)** `integer` — The EVM chain id the recipient + assets live on. Required by ERC-1271 smart-wallet verifiers that re-hash typed-data using the wallet's own chainId. - **`name` (required)** `string`, possible values: `"Glider Withdrawal Authorization"` - **`verifyingContract` (required)** `string` — The smart account address being debited (bare EVM address, not a CAIP-10). Binds the signature to this specific smart account deployment. Documented exception to the \`\*AccountId\` rule — dictated by EIP-712. - **`version` (required)** `string`, possible values: `"1", "2"` - **`message` (required)** `object` - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units to withdraw as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, possible values: `true` — Present (and \`true\`) only on a liquidation (version-"2" message); the \`assets\` are swapped to \`settlementAssetId\` and delivered to the recipient. Omitted for plain transfers. Echoed verbatim from stage 1. - **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as the recipient and assets: configured USDC or USDT for an EVM liquidation, or USDC for a Solana liquidation. Cross-chain settlement is not supported. Present only on a liquidation (version-"2" message), omitted for plain transfers. Echoed verbatim from stage 1. - **`primaryType` (required)** `string`, possible values: `"Withdrawal"` - **`types` (required)** `object` - **`Withdrawal` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` - **`WithdrawalAsset` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "authorizationId": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": "2026-04-17T12:10:00.000Z", "typedData": { "primaryType": "Withdrawal", "domain": { "name": "Glider Withdrawal Authorization", "version": "1", "chainId": 1, "verifyingContract": "0x2222222222222222222222222222222222222222" }, "types": { "Withdrawal": [ { "name": "", "type": "" } ], "WithdrawalAsset": [ { "name": "", "type": "" } ] }, "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } }, "authorization": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "" } } } } ``` ##### Status: 400 Validation error: invalid recipient, duplicate assets, chain mismatch, insufficient balance, portfolio has no smart account on the recipient's chain, or an unsupported liquidation settlement asset ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found or not owned by tenant ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Submit a signed withdrawal authorization - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/withdraw` - **Tags:** Portfolios Stage 2 of the two-stage withdraw flow. Accepts the inner `message` echoed verbatim from stage 1 (`typedData.message` for EVM, `authorization.message` for Solana) and the user's `signature`. Verifies ownership, re-checks live balances, validates the signature was produced by the portfolio owner, and dispatches the onchain withdrawal — EVM via Inngest, Solana via a direct paymaster-sponsored transfer. Idempotent on `message.nonce` — retries with the same message + signature replay the cached 202 response. Returns immediately with an `operationId` that integrators can poll for onchain confirmation. #### Request Body ##### Content-Type: application/json - **`message` (required)** `object` — The inner \`message\` body from the stage-1 response, echoed verbatim — \`typedData.message\` (EVM) or \`authorization.message\` (Solana). The server reconstructs the signed payload and verifies the signature against the portfolio owner. - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) unit amount as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, default: `false` — Echoed verbatim from stage 1. When true, the authorization swaps \`assets\` to \`settlementAssetId\` and delivers it to the recipient. Defaults to false if omitted. - **`settlementAssetId`** `string` — Echoed verbatim from stage 1. CAIP-19 settlement asset on the same chain as \`recipientAccountId\` and every \`assets\[].assetId\`: configured USDC or USDT for an EVM withdrawal, or USDC for a Solana withdrawal. It does not enable cross-chain delivery or bridging. Omitted for plain transfers. - **`signature` (required)** `string` — User's signature over the stage-1 authorization. EVM = \`0x\`-hex EIP-712/EIP-191 (ECDSA EOA or ERC-1271). Solana Model A (EVM-rooted) = \`0x\`-hex EIP-191; Model B (Solana-rooted) = base58 ed25519. **Example:** ```json { "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": false, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" }, "signature": "0x9412d70d539f889ecec2d3152b68af758d689a4325a43b07811ee708814527c72256fc749d7fd3745a07f0aaa84813955050c461392d9b9ee1f80e106fac39e01b" } ``` #### Responses ##### Status: 202 Withdrawal accepted and dispatched. Onchain confirmation is async. ###### Content-Type: application/json - **`data` (required)** `object` - **`operationId` (required)** `string` — Operation identifier to poll with \`GET /v2/portfolios/{portfolioId}/operations/{operationId}\` for onchain confirmation. - **`submittedAt` (required)** `string` — ISO 8601 timestamp when the withdrawal was dispatched - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4", "submittedAt": "2026-04-17T12:05:00.000Z" } } ``` ##### Status: 400 Validation error: expired authorization, portfolio-id mismatch, invalid signature, insufficient balance, an unsupported settlement asset, or malformed message ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found or not owned by tenant ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 409 Idempotency replay-in-progress or key-conflict ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 503 Signature verifier is temporarily unavailable — retry ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Prepare a full-portfolio liquidation for user signing - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/liquidate-all/signature` - **Tags:** Portfolios Stage 1 of the two-stage liquidate-all flow. Enumerates every holding on the recipient's chain whose value is above the tenant swap threshold, then returns a signable authorization that swaps them all to the `settlementAssetId` settlement asset (USDC by default; USDT also allowed on EVM) and delivers it to the recipient. Sub-threshold/illiquid dust is left in the vault (best-effort empty). EVM liquidations receive an EIP-712 typed-data object under `data.typedData`; Solana liquidations receive an off-chain authorization under `data.authorization` (`kind: "ecdsa"` — EVM-rooted Model A, signed via EIP-191; or `kind: "solana-message"` — Solana-rooted Model B, signed via ed25519). Stage 2 (`POST /v2/portfolios/{portfolioId}/liquidate-all`) accepts the echoed `message` plus the owner's signature. #### Request Body ##### Content-Type: application/json - **`recipientAccountId` (required)** `string` — CAIP-10 recipient on the chain to liquidate — EVM (\`eip155:\:\\`) or Solana (\`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\`). Every holding on that chain above the tenant swap threshold is swapped to the \`settlementAssetId\` settlement asset (USDC by default) and delivered here. Holdings on other chains are untouched — liquidate each chain separately. \`settlementAssetId\` must use this same chain; cross-chain delivery and bridging are not supported. - **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as \`recipientAccountId\`. For an EVM liquidation, use configured USDC or USDT on that EVM chain. For a Solana liquidation, use Solana USDC. Omit to default to USDC on the liquidation chain. This field does not select a different destination chain or enable bridging. **Example:** ```json { "recipientAccountId": "eip155:8453:0x4444444444444444444444444444444444444444", "settlementAssetId": "eip155:56/erc20:0x55d398326f99059fF775485246999027B3197955" } ``` #### Responses ##### Status: 200 Liquidation authorization prepared; user must sign the returned typed data ###### Content-Type: application/json - **`data` (required)** `object` - **`authorizationId` (required)** `string` — Opaque 32-byte hex nonce. Use as the idempotency anchor for stage 2 retries of the same signed authorization. - **`expiresAt` (required)** `string` — ISO 8601 timestamp after which the authorization cannot be submitted. Matches the signed \`expiresAt\` (Unix seconds). - **`authorization`** `object` — Solana portfolios only. The off-chain authorization to sign with the portfolio owner's wallet — \`kind: "ecdsa"\` (EVM-rooted Model A; sign \`raw\` via EIP-191) or \`kind: "solana-message"\` (Solana-rooted Model B; sign \`text\` via ed25519). Echo \`authorization.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. - **`typedData`** `object` — EVM portfolios only. Full EIP-712 typed-data object. Pass directly to \`signTypedData(...)\` in the user's wallet; echo \`typedData.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. - **`domain` (required)** `object` - **`chainId` (required)** `integer` — The EVM chain id the recipient + assets live on. Required by ERC-1271 smart-wallet verifiers that re-hash typed-data using the wallet's own chainId. - **`name` (required)** `string`, possible values: `"Glider Withdrawal Authorization"` - **`verifyingContract` (required)** `string` — The smart account address being debited (bare EVM address, not a CAIP-10). Binds the signature to this specific smart account deployment. Documented exception to the \`\*AccountId\` rule — dictated by EIP-712. - **`version` (required)** `string`, possible values: `"1", "2"` - **`message` (required)** `object` - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units to withdraw as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, possible values: `true` — Present (and \`true\`) only on a liquidation (version-"2" message); the \`assets\` are swapped to \`settlementAssetId\` and delivered to the recipient. Omitted for plain transfers. Echoed verbatim from stage 1. - **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as the recipient and assets: configured USDC or USDT for an EVM liquidation, or USDC for a Solana liquidation. Cross-chain settlement is not supported. Present only on a liquidation (version-"2" message), omitted for plain transfers. Echoed verbatim from stage 1. - **`primaryType` (required)** `string`, possible values: `"Withdrawal"` - **`types` (required)** `object` - **`Withdrawal` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` - **`WithdrawalAsset` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "authorizationId": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": "2026-04-17T12:10:00.000Z", "typedData": { "primaryType": "Withdrawal", "domain": { "name": "Glider Withdrawal Authorization", "version": "1", "chainId": 1, "verifyingContract": "0x2222222222222222222222222222222222222222" }, "types": { "Withdrawal": [ { "name": "", "type": "" } ], "WithdrawalAsset": [ { "name": "", "type": "" } ] }, "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } }, "authorization": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "" } } } } ``` ##### Status: 400 Validation error: invalid recipient, USDC unsupported on the chain, an unsupported settlement asset, portfolio has no smart account on the chain, insufficient live balance, or nothing above the liquidation threshold ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope, or the Solana B2B API is not enabled for this tenant ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found or not owned by tenant ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Submit a signed full-portfolio liquidation - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/liquidate-all` - **Tags:** Portfolios Stage 2 of the two-stage liquidate-all flow. Accepts the `message` echoed verbatim from `POST /v2/portfolios/{portfolioId}/liquidate-all/signature` plus the owner's `signature`, verifies ownership, re-checks live balances, and dispatches the same-chain swap to the signed `settlementAssetId` settlement asset (configured USDC or USDT on EVM; USDC on Solana) + delivery to the same-chain recipient. Cross-chain delivery and bridging are not supported. Idempotent on `message.nonce`. Returns an `operationId` to poll. Functionally identical to `POST /v2/portfolios/{portfolioId}/withdraw` with a `liquidate: true` authorization. #### Request Body ##### Content-Type: application/json - **`message` (required)** `object` — The inner \`message\` body from the stage-1 response, echoed verbatim — \`typedData.message\` (EVM) or \`authorization.message\` (Solana). The server reconstructs the signed payload and verifies the signature against the portfolio owner. - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) unit amount as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, default: `false` — Echoed verbatim from stage 1. When true, the authorization swaps \`assets\` to \`settlementAssetId\` and delivers it to the recipient. Defaults to false if omitted. - **`settlementAssetId`** `string` — Echoed verbatim from stage 1. CAIP-19 settlement asset on the same chain as \`recipientAccountId\` and every \`assets\[].assetId\`: configured USDC or USDT for an EVM withdrawal, or USDC for a Solana withdrawal. It does not enable cross-chain delivery or bridging. Omitted for plain transfers. - **`signature` (required)** `string` — User's signature over the stage-1 authorization. EVM = \`0x\`-hex EIP-712/EIP-191 (ECDSA EOA or ERC-1271). Solana Model A (EVM-rooted) = \`0x\`-hex EIP-191; Model B (Solana-rooted) = base58 ed25519. **Example:** ```json { "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": false, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" }, "signature": "0x9412d70d539f889ecec2d3152b68af758d689a4325a43b07811ee708814527c72256fc749d7fd3745a07f0aaa84813955050c461392d9b9ee1f80e106fac39e01b" } ``` #### Responses ##### Status: 202 Liquidation accepted and dispatched. Onchain confirmation is async. ###### Content-Type: application/json - **`data` (required)** `object` - **`operationId` (required)** `string` — Operation identifier to poll with \`GET /v2/portfolios/{portfolioId}/operations/{operationId}\` for onchain confirmation. - **`submittedAt` (required)** `string` — ISO 8601 timestamp when the withdrawal was dispatched - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4", "submittedAt": "2026-04-17T12:05:00.000Z" } } ``` ##### Status: 400 Validation error: expired authorization, portfolio-id mismatch, invalid signature, insufficient balance, USDC unsupported on the chain, an unsupported settlement asset, or malformed message ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found or not owned by tenant ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 409 Idempotency replay-in-progress or key-conflict ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 503 Signature verifier is temporarily unavailable — retry ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get the signable message for activating chains on a portfolio - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/chains/signature` - **Tags:** Portfolios Stage 1 of the two-stage chain-activation flow. Recomputes the session-key message over the requested (new) chains from the portfolio's existing owner, operating agent, and account index, and returns it for the portfolio owner to sign. Stateless and deterministic — no reservation is made and repeating the call returns the same message. Pass the owner's signature to `POST /v2/portfolios/{portfolioId}/chains` to activate. The message shape follows the portfolio's account type (determined server-side): ECDSA portfolios sign a merkle root covering all requested chains at once; ERC-1271 portfolios sign per-chain EIP-712 typed data and must activate one chain per request. EVM portfolios only: Solana portfolios are rejected. #### Request Body ##### Content-Type: application/json - **`chainIds` (required)** `array` — Numeric chain ids to activate on the portfolio. Must be a subset of the chains this deployment has RPCs configured for, must not contain duplicates, and must not include chains the portfolio is already active on. ERC-1271 portfolios sign one chain per signature, so they must pass exactly one chain id. **Items:** `integer` **Example:** ```json { "chainIds": [ 42161 ] } ``` #### Responses ##### Status: 200 Signable chain-activation message issued ###### Content-Type: application/json - **`data` (required)** `object` - **`message` (required)** `object` — The signable chain-activation message. Deterministic for a given (portfolio, chainIds) pair — repeating this call returns the same message. ECDSA portfolios get \`{ kind: "ecdsa", raw }\` (a session-key merkle root over the requested chains, signed via EIP-191 personal\_sign); ERC-1271 portfolios get \`{ kind: "typed-data", typedData }\` (EIP-712 payload signed with the owner's smart-contract wallet). - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "message": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" } } } ``` ##### Status: 400 Invalid request, chain already active, unsupported portfolio (Solana), or more than one chain requested on an ERC-1271 portfolio ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Activate chains on an existing portfolio - **Method:** `POST` - **Path:** `/portfolios/{portfolioId}/chains` - **Tags:** Portfolios Stage 2 of the two-stage chain-activation flow. Verifies the owner's signature over the session-key message for the requested chains (recomputed server-side from the portfolio's persisted owner, agent, and account index), then creates one smart account per chain inside a single transaction. ECDSA portfolios may activate several chains under one signature; ERC-1271 portfolios activate exactly one chain per request, verified against the owner contract on that chain. The operation is idempotent on the signed payload: retrying with the same `chainIds` + `signature` replays the original response; a concurrent identical request returns 409. Activating a chain the portfolio already has returns 400. #### Request Body ##### Content-Type: application/json - **`chainIds` (required)** `array` — Numeric chain ids to activate (no duplicates). Must exactly match the \`chainIds\` passed to \`POST /v2/portfolios/{portfolioId}/chains/signature\` — the signature was produced over that set. ERC-1271 portfolios activate one chain per request. **Items:** `integer` - **`signature` (required)** `string` — The portfolio owner's signature over the message returned by \`POST /v2/portfolios/{portfolioId}/chains/signature\`: an EIP-191 personal\_sign signature over \`message.raw\` for ECDSA portfolios, or the smart-contract wallet's ERC-1271 signature over \`message.typedData\` for ERC-1271 portfolios. **Example:** ```json { "chainIds": [ 42161 ], "signature": "0x9412d70d539f889ecec2d3152b68af758d689a4325a43b07811ee708814527c72256fc749d7fd3745a07f0aaa84813955050c461392d9b9ee1f80e106fac39e01b" } ``` #### Responses ##### Status: 201 Chains activated ###### Content-Type: application/json - **`data` (required)** `object` - **`portfolioId` (required)** `string` — Portfolio identifier - **`smartAccounts` (required)** `array` — Canonical SmartAccount objects, one per newly activated chain. Deterministic CREATE2 addresses — the same address as the portfolio's existing smart accounts, now live on the new chains. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ] } } ``` ##### Status: 400 Invalid request, invalid signature, chain already active, unsupported portfolio (Solana), or more than one chain requested on an ERC-1271 portfolio ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 409 An identical activation request is still in flight ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get the status of an async operation on a portfolio - **Method:** `GET` - **Path:** `/portfolios/{portfolioId}/operations/{operationId}` - **Tags:** Portfolios Polls the execution state of an operation dispatched via a write endpoint (`/withdraw`, `/trigger`, etc.). Operations transition through `accepted → running → completed | failed | cancelled`; poll at 2–5s intervals until a terminal state. #### Responses ##### Status: 200 Current operation status ###### Content-Type: application/json - **`data` (required)** `object` - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`error` (required)** `string | null` — Free-form error message. Populated only when the operation reaches \`failed\` or \`cancelled\`. - **`finishedAt` (required)** `string | null` — ISO 8601 timestamp at which the operation reached a terminal state. Null while in-flight. - **`kind` (required)** `string`, possible values: `"withdraw", "rebalance", "bridge", "swap", "deposit", "transfer", "execution"` — Kind of async operation. Values are emitted by v2 portfolio writes, execution streams, and internal rebalance/swap/bridge flows. - **`operationId` (required)** `string` — Async operation identifier - **`portfolioId` (required)** `string` — Portfolio identifier - **`state` (required)** `string`, possible values: `"accepted", "running", "retrying", "awaiting_user", "completed", "failed", "cancelled"` — Current execution state. Terminal states: \`completed\`, \`failed\`, \`cancelled\`. - **`updatedAt` (required)** `string` — ISO 8601 last-update timestamp - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4", "portfolioId": "a1b2c3d4", "kind": "withdraw", "state": "running", "createdAt": "2026-04-17T12:00:00.000Z", "updatedAt": "2026-04-17T12:05:00.000Z", "finishedAt": "2026-04-17T12:05:00.000Z", "error": null } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio or operation not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Patch portfolio metadata - **Method:** `PATCH` - **Path:** `/portfolios/{portfolioId}` - **Tags:** Portfolios Patches portfolio metadata. JSON Merge Patch (RFC 7396): omit to preserve, `null` to clear, string to set. Empty body `{}` is a 200 no-op. Body is strict; unknown keys return 400. Cross-tenant access returns 404. #### Request Body ##### Content-Type: application/json - **`portfolioName`** `string | null` — Integrator-provided display name for the portfolio. Trimmed server-side. Max 64 characters. Supports Unicode letters, digits, spaces, and - \_ . ' : ( ) & /. **Example:** ```json { "portfolioName": "Alice's Portfolio" } ``` #### Responses ##### Status: 200 Patched portfolio detail ###### Content-Type: application/json - **`data` (required)** `object` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ##### Status: 400 Invalid patch body ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get portfolio detail - **Method:** `GET` - **Path:** `/portfolios/{portfolioId}` - **Tags:** Portfolios Returns a single portfolio owned by the authenticated tenant. DB-only projection — identity, strategy, smart accounts, and schedule state. The `schedule` block is the canonical source for runtime rebalance visibility: `status` (active vs paused), `frequency`/`intervalMs` (cadence), `nextDueAt` (when the next automated rebalance will fire), and `lastRebalanceAt` (when the most recent run completed). Cross-tenant access returns 404 (no existence leak). For live balances call `GET /v2/portfolios/{portfolioId}/positions`. #### Responses ##### Status: 200 Portfolio detail ###### Content-Type: application/json - **`data` (required)** `object` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Portfolio not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get asset allocation category breakdown - **Method:** `POST` - **Path:** `/assets/allocation-breakdown` - **Tags:** Assets Resolves canonical assets or chain-scoped CAIP-19 assets to canonical identities, then aggregates the requested holdings across sector, industry, Glider theme, Glider sector, or CoinGecko category dimensions. #### Request Body ##### Content-Type: application/json - **`holdings` (required)** `array` **Items:** - **`assetCanonicalId`** `string | null`, format: `uuid` - **`caipAssetId`** `string | null` - **`marketValueUsd`** `string | null` - **`name`** `string | null` - **`symbol`** `string | null` - **`weight`** `string | null` - **`dimensions`** `array` **Items:** `string`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory"` - **`includeHoldings`** `boolean` - **`multiCategoryMode`** `string`, possible values: `"primary", "apportioned", "overlap"` **Example:** ```json { "dimensions": [ "sector" ], "holdings": [ { "assetCanonicalId": null, "caipAssetId": null, "marketValueUsd": null, "name": null, "symbol": null, "weight": null } ], "includeHoldings": true, "multiCategoryMode": "primary" } ``` #### Responses ##### Status: 200 Asset allocation category breakdown ###### Content-Type: application/json - **`data` (required)** `object` - **`breakdowns` (required)** `array` **Items:** - **`absoluteTotalWeight` (required)** `string` - **`aggregationMode` (required)** `string`, possible values: `"apportioned", "overlap", "primary", "single"` - **`buckets` (required)** `array` **Items:** - **`absoluteWeight` (required)** `string` - **`holdingCount` (required)** `integer` - **`holdings` (required)** `array` **Items:** - **`absoluteWeight` (required)** `string` - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`contributionWeight` (required)** `string` - **`inputIndex` (required)** `integer` - **`name` (required)** `string | null` - **`resolutionPath` (required)** `string`, possible values: `"input_canonical", "product_route", "token_subject_link", "unresolved"` - **`symbol` (required)** `string | null` - **`key` (required)** `string` - **`label` (required)** `string` - **`weight` (required)** `string` - **`dimension` (required)** `string`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory"` - **`totalMayExceedOne` (required)** `boolean` - **`totalWeight` (required)** `string` - **`diagnostics` (required)** `object` - **`lowConfidence` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`confidence` (required)** `integer` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`sectorClassification` (required)** `object` - **`asOfDate` (required)** `string | null` - **`confidence` (required)** `integer` - **`displaySector` (required)** `string` - **`resolvedAt` (required)** `string` - **`resolverVersion` (required)** `string` - **`sicCode` (required)** `string | null` - **`sicDescription` (required)** `string | null` - **`source` (required)** `string` - **`sourceIndustry` (required)** `string | null` - **`sourceIndustryGroup` (required)** `string | null` - **`sourceKeyType` (required)** `string | null` - **`sourceKeyValue` (required)** `string | null` - **`sourceRank` (required)** `integer` - **`sourceSector` (required)** `string | null` - **`sourceSubIndustry` (required)** `string | null` - **`taxonomy` (required)** `string`, possible values: `"internal_display_sector_v1"` - **`symbol` (required)** `string | null` - **`unclassified` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`unresolved` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`unsupported` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`holdings` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`inputIndex` (required)** `integer` - **`name` (required)** `string | null` - **`normalizedWeight` (required)** `string` - **`sourceValue` (required)** `string` - **`symbol` (required)** `string | null` - **`normalization` (required)** `object` - **`inputMode` (required)** `string`, possible values: `"equal", "marketValueUsd", "weights"` - **`normalizedTotal` (required)** `string` - **`sourceTotal` (required)** `string` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "breakdowns": [ { "absoluteTotalWeight": "", "aggregationMode": "apportioned", "buckets": [ { "absoluteWeight": "", "holdingCount": 0, "holdings": [ { "absoluteWeight": "", "assetCanonicalId": null, "caipAssetId": null, "contributionWeight": "", "inputIndex": 0, "name": null, "resolutionPath": "input_canonical", "symbol": null } ], "key": "", "label": "", "weight": "" } ], "dimension": "sector", "totalMayExceedOne": true, "totalWeight": "" } ], "diagnostics": { "lowConfidence": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null, "confidence": 0, "sectorClassification": { "asOfDate": null, "confidence": 0, "displaySector": "", "resolverVersion": "", "resolvedAt": "", "sicCode": null, "sicDescription": null, "source": "", "sourceIndustry": null, "sourceIndustryGroup": null, "sourceKeyType": null, "sourceKeyValue": null, "sourceRank": 1, "sourceSector": null, "sourceSubIndustry": null, "taxonomy": "internal_display_sector_v1" } } ], "unclassified": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null } ], "unresolved": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null } ], "unsupported": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null } ] }, "holdings": [ { "assetCanonicalId": null, "caipAssetId": null, "inputIndex": 0, "name": null, "normalizedWeight": "", "sourceValue": "", "symbol": null } ], "normalization": { "inputMode": "equal", "normalizedTotal": "", "sourceTotal": "" } } } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### Get campaign portfolios - **Method:** `GET` - **Path:** `/campaigns/{campaignId}/strategies/{strategyId}/portfolios` - **Tags:** Campaigns Returns paginated portfolios for a campaign-strategy pair. Validates that the requesting tenant owns the campaign and that the strategy ID matches the campaign configuration. #### Responses ##### Status: 200 Campaign portfolios with TVL ###### Content-Type: application/json - **`data` (required)** `object` - **`campaignId` (required)** `string` - **`portfolios` (required)** `array` **Items:** - **`assets` (required)** `array` **Items:** - **`assetId` (required)** `string` - **`balance` (required)** `string` — Human-readable token balance - **`balanceRaw` (required)** `string` — Raw integer token balance (no decimals applied) - **`decimals` (required)** `integer` - **`symbol` (required)** `string` - **`valueUsd` (required)** `string` — USD value, formatted to 6 decimal places - **`createdAt` (required)** `string` — ISO 8601 timestamp - **`portfolioId` (required)** `string` — Unique portfolio identifier - **`totalValueUsd` (required)** `string` — Total value locked in USD, formatted to 6 decimal places - **`vaults` (required)** `array` **Items:** - **`vaultId` (required)** `string` - **`strategyId` (required)** `string` - **`nextCursor` (required)** `string | null` - **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "campaignId": "", "strategyId": "", "portfolios": [ { "portfolioId": "", "totalValueUsd": "1500.500000", "vaults": [ { "vaultId": "eip155:1:0xe3a2d1f49aee887e42655b56371d4d76bbf58058" } ], "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "valueUsd": "500.013232", "symbol": "USDC", "balance": "500.013232", "balanceRaw": "500013232", "decimals": 6 } ], "createdAt": "2025-01-01T10:00:00.000Z" } ] }, "nextCursor": null } ``` ##### Status: 400 Invalid request ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 401 Missing or invalid API key ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 403 Missing required scope or tenant not authorized for campaign ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 404 Campaign or strategy not found ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ##### Status: 500 Internal server error ###### Content-Type: application/json - **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` - **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ## Schemas ### ScopesResponse - **Type:**`object` * **`data` (required)** `object` - **`scopes` (required)** `array` **Items:** - **`description` (required)** `string` — Human-readable description - **`name` (required)** `string`, possible values: `"strategies:read", "strategies:write", "portfolios:read", "portfolios:write", "portfolios:withdraw", "enroll:write", "tenant:read", "tenant:write", "fees:read", "fees:write"` — Canonical scope identifier (\`resource:action\`) - **`tier` (required)** `string`, possible values: `"default", "standard", "restricted"` — Granting tier: \`default\` (auto-granted), \`standard\` (self-service), \`restricted\` (admin-only) * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "scopes": [ { "name": "strategies:read", "description": "List and view strategies", "tier": "default" } ] } } ``` ### ScopeEntry - **Type:**`object` * **`description` (required)** `string` — Human-readable description * **`name` (required)** `string`, possible values: `"strategies:read", "strategies:write", "portfolios:read", "portfolios:write", "portfolios:withdraw", "enroll:write", "tenant:read", "tenant:write", "fees:read", "fees:write"` — Canonical scope identifier (\`resource:action\`) * **`tier` (required)** `string`, possible values: `"default", "standard", "restricted"` — Granting tier: \`default\` (auto-granted), \`standard\` (self-service), \`restricted\` (admin-only) **Example:** ```json { "name": "strategies:read", "description": "List and view strategies", "tier": "default" } ``` ### WhoamiResponse - **Type:**`object` * **`data` (required)** `object` - **`apiKeyId` (required)** `string | null` — API key record ID. Null only for legacy keys that have not migrated to better-auth. - **`scopes` (required)** `array` — Granted scopes for this API key **Items:** `string`, possible values: `"strategies:read", "strategies:write", "portfolios:read", "portfolios:write", "portfolios:withdraw", "enroll:write", "tenant:read", "tenant:write", "fees:read", "fees:write"` — Canonical scope identifier (\`resource:action\`) - **`tenantEmail` (required)** `string` — Tenant contact email - **`tenantName` (required)** `string` — Display name of the tenant * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "tenantName": "Integrator", "tenantEmail": "dev@integrator.example", "apiKeyId": "key_01JWZEE2MF30KVRMRX53N88VA4", "scopes": [ "strategies:read", "portfolios:read" ] } } ``` ### V2ErrorResponse - **Type:**`object` * **`error` (required)** `object` - **`code` (required)** `string` - **`message` (required)** `string` - **`details`** `array` **Items:** `string` * **`success` (required)** `boolean`, possible values: `false` **Example:** ```json { "success": false, "error": { "code": "", "message": "", "details": [ "" ] } } ``` ### ListDiscoveryStrategiesResponse - **Type:**`object` * **`data` (required)** `object` - **`strategies` (required)** `array` **Items:** - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`canMirror` (required)** `boolean`, possible values: `true` — Always true — only mirrorable strategies appear here. Use \`strategyId\` with the enroll flow to mirror. - **`createdAt` (required)** `string | null` — ISO 8601 creation timestamp of the strategy. Null when unknown. - **`description` (required)** `string | null` — Strategy description. Null when none was provided. - **`metrics` (required)** `object` - **`performance` (required)** `object` - **`summary` (required)** `object` — Target-allocation performance windows (1d…12m), same shape as \`GET /v2/strategies/{strategyId}/performance\`. \`windows\` is empty when price history is too short. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. - **`portfolioCount` (required)** `integer | null` — Number of portfolios created from this strategy. Null when the value is temporarily unavailable — never conflated with a real 0. - **`tvlUsd` (required)** `string | null` — Total value locked across the strategy's active portfolios, as a USD decimal string rounded to 2 decimal places. Null when the value is temporarily unavailable — never conflated with a real "0.00". - **`name` (required)** `string` — Display name for the strategy. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not a computed return. Absent when no APY is advertised. * **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategies": [ { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "createdAt": "2026-04-17T12:00:00.000Z", "metrics": { "tvlUsd": "1250342.18", "portfolioCount": 421, "performance": { "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } }, "canMirror": true } ] }, "nextCursor": null } ``` ### DiscoveryStrategyItem - **Type:**`object` * **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. * **`canMirror` (required)** `boolean`, possible values: `true` — Always true — only mirrorable strategies appear here. Use \`strategyId\` with the enroll flow to mirror. * **`createdAt` (required)** `string | null` — ISO 8601 creation timestamp of the strategy. Null when unknown. * **`description` (required)** `string | null` — Strategy description. Null when none was provided. * **`metrics` (required)** `object` - **`performance` (required)** `object` - **`summary` (required)** `object` — Target-allocation performance windows (1d…12m), same shape as \`GET /v2/strategies/{strategyId}/performance\`. \`windows\` is empty when price history is too short. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. - **`portfolioCount` (required)** `integer | null` — Number of portfolios created from this strategy. Null when the value is temporarily unavailable — never conflated with a real 0. - **`tvlUsd` (required)** `string | null` — Total value locked across the strategy's active portfolios, as a USD decimal string rounded to 2 decimal places. Null when the value is temporarily unavailable — never conflated with a real "0.00". * **`name` (required)** `string` — Display name for the strategy. * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not a computed return. Absent when no APY is advertised. **Example:** ```json { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "createdAt": "2026-04-17T12:00:00.000Z", "metrics": { "tvlUsd": "1250342.18", "portfolioCount": 421, "performance": { "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } }, "canMirror": true } ``` ### StrategyAllocation - **Type:**`object` * **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. **Example:** ```json { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] } ``` ### StrategyAllocationAsset - **Type:**`object` * **`assetId` (required)** `string` — CAIP-19 asset identifier * **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. **Example:** ```json { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ``` ### DiscoveryStrategyMetrics - **Type:**`object` * **`performance` (required)** `object` - **`summary` (required)** `object` — Target-allocation performance windows (1d…12m), same shape as \`GET /v2/strategies/{strategyId}/performance\`. \`windows\` is empty when price history is too short. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. * **`portfolioCount` (required)** `integer | null` — Number of portfolios created from this strategy. Null when the value is temporarily unavailable — never conflated with a real 0. * **`tvlUsd` (required)** `string | null` — Total value locked across the strategy's active portfolios, as a USD decimal string rounded to 2 decimal places. Null when the value is temporarily unavailable — never conflated with a real "0.00". **Example:** ```json { "tvlUsd": "1250342.18", "portfolioCount": 421, "performance": { "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } } ``` ### DiscoveryStrategyPerformance - **Type:**`object` * **`summary` (required)** `object` — Target-allocation performance windows (1d…12m), same shape as \`GET /v2/strategies/{strategyId}/performance\`. \`windows\` is empty when price history is too short. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. **Example:** ```json { "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } ``` ### StrategyPerformanceSummary - **Type:**`object` Target-allocation performance windows (1d…12m), same shape as `GET /v2/strategies/{strategyId}/performance`. `windows` is empty when price history is too short. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. **Example:** ```json { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } ``` ### ValidateStrategyResponse - **Type:**`object` * **`data` (required)** `object` - **`valid` (required)** `boolean`, possible values: `true` — Always \`true\` on a 2xx response. Validation failures return 400 with the same error shape the create endpoint would return. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "valid": true } } ``` ### ValidateStrategyData - **Type:**`object` * **`valid` (required)** `boolean`, possible values: `true` — Always \`true\` on a 2xx response. Validation failures return 400 with the same error shape the create endpoint would return. **Example:** ```json { "valid": true } ``` ### CreateStrategyRequest - **Type:**`object` * **`allocation` (required)** `object` * **`name` (required)** `string` — Display name for the strategy * **`schedule` (required)** `object` — Rebalance schedule — when to rebalance. * **`description`** `string | null`, default: `null` — Optional description of the strategy * **`isPublic`** `boolean`, default: `false` — Whether the strategy is publicly discoverable * **`preferences`** `object` — Optional swap execution constraints. System defaults apply if omitted. - **`swap` (required)** `object` - **`priceImpactBps`** `integer` — Max price impact in basis points (0–1000). Omit to use the system default. - **`slippageBps`** `integer` — Max slippage in basis points (0–1000). Omit to use the system default. - **`thresholdUsd`** `string` — Minimum swap size in USD as a decimal string (>= 1.00). Omit to use the system default. **Example:** ```json { "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "allocation": null, "schedule": { "type": "interval", "frequency": "daily" }, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false } ``` ### StrategySchedule - **Type:** Rebalance schedule — when to rebalance. **Example:** ### PreferencesCreate - **Type:**`object` Optional swap execution constraints. System defaults apply if omitted. - **`swap` (required)** `object` - **`priceImpactBps`** `integer` — Max price impact in basis points (0–1000). Omit to use the system default. - **`slippageBps`** `integer` — Max slippage in basis points (0–1000). Omit to use the system default. - **`thresholdUsd`** `string` — Minimum swap size in USD as a decimal string (>= 1.00). Omit to use the system default. **Example:** ```json { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } ``` ### SwapPreferencesCreateFields - **Type:**`object` * **`priceImpactBps`** `integer` — Max price impact in basis points (0–1000). Omit to use the system default. * **`slippageBps`** `integer` — Max slippage in basis points (0–1000). Omit to use the system default. * **`thresholdUsd`** `string` — Minimum swap size in USD as a decimal string (>= 1.00). Omit to use the system default. **Example:** ```json { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } ``` ### CreateStrategyResponse - **Type:**`object` * **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ### Strategy - **Type:**`object` * **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. * **`createdAt` (required)** `string` — ISO 8601 creation timestamp * **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. * **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. * **`name` (required)** `string` — Display name for the strategy * **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. * **`schedule` (required)** `object` * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. * **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. **Example:** ```json { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } ``` ### PreferencesView - **Type:**`object` Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. **Example:** ```json { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } ``` ### SwapPreferencesFields - **Type:**`object` * **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. * **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. * **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. **Example:** ```json { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } ``` ### ListStrategiesResponse - **Type:**`object` * **`data` (required)** `object` - **`strategies` (required)** `array` **Items:** - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. * **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategies": [ { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } ] }, "nextCursor": null } ``` ### StrategyListItem - **Type:**`object` * **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. * **`createdAt` (required)** `string` — ISO 8601 creation timestamp * **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. * **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. * **`name` (required)** `string` — Display name for the strategy * **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. * **`schedule` (required)** `object` * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. * **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. **Example:** ```json { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } ``` ### GetStrategyPreferencesResponse - **Type:**`object` * **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ### GetStrategyFeesResponse - **Type:**`object` * **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ### FeesView - **Type:**`object` * **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. **Example:** ```json { "swapBps": 50 } ``` ### GetStrategyScheduleResponse - **Type:**`object` * **`data` (required)** `object` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "type": "interval", "frequency": "daily" } } ``` ### GetStrategyPerformanceResponse - **Type:**`object` * **`data` (required)** `object` - **`meta` (required)** `object` - **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. - **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. - **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. - **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. - **`points` (required)** `array` — Daily chart points for the strategy performance curve. **Items:** - **`date` (required)** `string` — UTC calendar date for this point. - **`percentChange` (required)** `string` — Cumulative return at this point under the response's \`meta.method\`. \`TWR\` is compounded from the first returned point; \`MWR\` is the money-weighted return, which reflects deposits and withdrawals. - **`schedule` (required)** `object` — Rebalance schedule — when to rebalance. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`summary`** `object` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "schedule": { "type": "interval", "frequency": "daily" }, "meta": { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" }, "points": [ { "date": "2026-04-30", "percentChange": "4.1234" } ], "summary": null } } ``` ### StrategyPerformance - **Type:**`object` * **`meta` (required)** `object` - **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. - **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. - **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. - **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. * **`points` (required)** `array` — Daily chart points for the strategy performance curve. **Items:** - **`date` (required)** `string` — UTC calendar date for this point. - **`percentChange` (required)** `string` — Cumulative return at this point under the response's \`meta.method\`. \`TWR\` is compounded from the first returned point; \`MWR\` is the money-weighted return, which reflects deposits and withdrawals. * **`schedule` (required)** `object` — Rebalance schedule — when to rebalance. * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`summary`** `object` **Example:** ```json { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "schedule": { "type": "interval", "frequency": "daily" }, "meta": { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" }, "points": [ { "date": "2026-04-30", "percentChange": "4.1234" } ], "summary": null } ``` ### StrategyPerformanceMeta - **Type:**`object` * **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. * **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. * **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. * **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. **Example:** ```json { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" } ``` ### StrategyPerformancePoint - **Type:**`object` * **`date` (required)** `string` — UTC calendar date for this point. * **`percentChange` (required)** `string` — Cumulative return at this point under the response's \`meta.method\`. \`TWR\` is compounded from the first returned point; \`MWR\` is the money-weighted return, which reflects deposits and withdrawals. **Example:** ```json { "date": "2026-04-30", "percentChange": "4.1234" } ``` ### ListStrategyVersionsResponse - **Type:**`object` * **`data` (required)** `object` - **`versions` (required)** `array` **Items:** - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`changeLog` (required)** `string | null` — Optional note from the publish call. \`null\` when not provided. - **`createdAt` (required)** `string` — ISO 8601 timestamp when this version was published. - **`isHead` (required)** `boolean` — True for the active version. Exactly one per strategy. - **`version` (required)** `integer` — Sequential version number, server-assigned. v1 at create; each publish increments by 1. * **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "versions": [ { "version": 3, "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "changeLog": "Increased USDC weight from 60% to 70%", "isHead": true, "createdAt": "2026-04-17T12:00:00.000Z" } ] }, "nextCursor": null } ``` ### StrategyVersion - **Type:**`object` * **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. * **`changeLog` (required)** `string | null` — Optional note from the publish call. \`null\` when not provided. * **`createdAt` (required)** `string` — ISO 8601 timestamp when this version was published. * **`isHead` (required)** `boolean` — True for the active version. Exactly one per strategy. * **`version` (required)** `integer` — Sequential version number, server-assigned. v1 at create; each publish increments by 1. **Example:** ```json { "version": 3, "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "changeLog": "Increased USDC weight from 60% to 70%", "isHead": true, "createdAt": "2026-04-17T12:00:00.000Z" } ``` ### PatchStrategyPreferencesResponse - **Type:**`object` * **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ### PreferencesPatch - **Type:**`object` * **`swap`** `object` - **`priceImpactBps`** `integer | null` — Max price impact in basis points (0–1000). Pass \`null\` to clear; omit to preserve. - **`slippageBps`** `integer | null` — Max slippage in basis points (0–1000). Pass \`null\` to clear; omit to preserve. - **`thresholdUsd`** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Pass \`null\` to clear; omit to preserve. **Example:** ```json { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } ``` ### SwapPreferencesPatchFields - **Type:**`object` * **`priceImpactBps`** `integer | null` — Max price impact in basis points (0–1000). Pass \`null\` to clear; omit to preserve. * **`slippageBps`** `integer | null` — Max slippage in basis points (0–1000). Pass \`null\` to clear; omit to preserve. * **`thresholdUsd`** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Pass \`null\` to clear; omit to preserve. **Example:** ```json { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } ``` ### PatchStrategyFeesResponse - **Type:**`object` * **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ### FeesPatch - **Type:**`object` * **`swapBps`** `integer | null` — Integrator swap fee in basis points (30–300). Pass \`null\` to clear; omit to preserve. **Example:** ```json { "swapBps": 50 } ``` ### PutStrategyScheduleResponse - **Type:**`object` * **`data` (required)** `object` — Rebalance schedule — when to rebalance. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "type": "interval", "frequency": "daily" } } ``` ### PublishStrategyVersionResponse - **Type:**`object` * **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`changeLog` (required)** `string | null` — Optional note from the publish call. \`null\` when not provided. - **`createdAt` (required)** `string` — ISO 8601 timestamp when this version was published. - **`isHead` (required)** `boolean` — True for the active version. Exactly one per strategy. - **`version` (required)** `integer` — Sequential version number, server-assigned. v1 at create; each publish increments by 1. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "version": 3, "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "changeLog": "Increased USDC weight from 60% to 70%", "isHead": true, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ### PublishStrategyVersionRequest - **Type:**`object` * **`allocation` (required)** `object` * **`changeLog`** `string | null` — Optional note (≤500 chars) shown in the version history. Two publishes with identical allocations but different notes are both accepted. **Example:** ```json { "allocation": null, "changeLog": "Increased USDC weight from 60% to 70%" } ``` ### GetStrategyResponse - **Type:**`object` * **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` — Rebalance schedule. Always populated for your own strategies (required at creation). Null only when reading a public strategy from another tenant whose creator has no schedule configured. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": { "type": "interval", "frequency": "daily" }, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ### StrategyDetail - **Type:**`object` * **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. * **`createdAt` (required)** `string` — ISO 8601 creation timestamp * **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. * **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. * **`name` (required)** `string` — Display name for the strategy * **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. * **`schedule` (required)** `object` — Rebalance schedule. Always populated for your own strategies (required at creation). Null only when reading a public strategy from another tenant whose creator has no schedule configured. * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. * **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. **Example:** ```json { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": { "type": "interval", "frequency": "daily" }, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } ``` ### PatchStrategyResponse - **Type:**`object` * **`data` (required)** `object` - **`allocation` (required)** `object` - **`assets` (required)** `array` — Target assets for the strategy. Weights must sum to 100. **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`weight` (required)** `string` — Allocation weight as a string percentage. Must be > 0, up to 2 decimal places. The allocation's weights must sum to 100. - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`description` (required)** `string | null` — Integrator-provided description. Null when the strategy was created without one. - **`isPublic` (required)** `boolean` — Whether the strategy is publicly discoverable by other tenants. - **`name` (required)** `string` — Display name for the strategy - **`preferences` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. - **`schedule` (required)** `object` - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`version` (required)** `integer` — Strategy revision counter. Increments on allocation updates. - **`maxApy`** `string` — Advertised maximum APY as a decimal percentage string (e.g. "10.00" = 10%). Managed by Glider; not settable through this API and not a computed return. Absent when no APY is advertised. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "maxApy": "10.00", "allocation": { "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "weight": "60" } ] }, "schedule": null, "preferences": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } }, "isPublic": false, "version": 1, "createdAt": "2026-04-17T12:00:00.000Z" } } ``` ### StrategyMetadataPatch - **Type:**`object` * **`description`** `string | null` — Integrator-provided description. Send \`null\` to clear. * **`isPublic`** `boolean` — Whether the strategy is publicly discoverable by other tenants. * **`name`** `string` — Display name for the strategy. Cannot be cleared. **Example:** ```json { "name": "Balanced Growth", "description": "Multi-chain balanced allocation strategy", "isPublic": false } ``` ### GetTenantPreferencesResponse - **Type:**`object` * **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ### PatchTenantPreferencesResponse - **Type:**`object` * **`data` (required)** `object` — Swap execution preferences. Inner fields are null when the strategy hasn't overridden them. - **`swap` (required)** `object` - **`priceImpactBps` (required)** `integer | null` — Max price impact in basis points (0–1000). Null when not configured. - **`slippageBps` (required)** `integer | null` — Max slippage in basis points (0–1000). Null when not configured. - **`thresholdUsd` (required)** `string | null` — Minimum swap size in USD as a decimal string (>= 1.00). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swap": { "slippageBps": 300, "priceImpactBps": 300, "thresholdUsd": "5.00" } } } ``` ### GetTenantFeesResponse - **Type:**`object` * **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ### PatchTenantFeesResponse - **Type:**`object` * **`data` (required)** `object` - **`swapBps` (required)** `integer | null` — Integrator swap fee in basis points (30–300). Null when not configured. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "swapBps": 50 } } ``` ### CreateEnrollSignatureResponse - **Type:**`object` * **`data` (required)** `object` - **`accountIndex` (required)** `string` — Reserved account index. Must be round-tripped to \`POST /v2/enroll\`. - **`agentAccountId` (required)** `string` — Pooled KMS agent as a chain-agnostic CAIP-10 identifier (\`eip155:0:\\`) that will operate the smart account post-enrollment. Must be round-tripped verbatim to \`POST /v2/enroll\`. - **`flowId` (required)** `string` — Opaque 24h reservation token. Must be round-tripped to \`POST /v2/enroll\` and also serves as the idempotency anchor there. - **`message` (required)** `object` — Discriminated union. ECDSA enrollment returns \`{ kind: "ecdsa", raw }\`; ERC-1271 enrollment returns \`{ kind: "typed-data", typedData }\`; SVM enrollment may return \`{ kind: "solana-message", text }\`. - **`accountType`** `string`, possible values: `"ECDSA", "ERC1271"` — EVM Kernel owner/validator configuration used to build \`message\`. Round-trip this to \`POST /v2/enroll\` when present. - **`depositAccountId`** `string` — SVM B2B subaccount path only: CAIP-10 of the Swig sub-account the user will deposit funds to once enrolled. Mirrors what \`POST /v2/enroll\` returns in \`smartAccounts\[].depositAccountId\`. - **`reusedSwig`** `boolean` — SVM B2B subaccount path only: \`true\` when an existing Swig PDA for this (tenant, user) is being reused (a subsequent vault), \`false\` when a new one will be created (the first vault). - **`solanaTransaction`** `string` — SVM B2B subaccount path only: the base64-serialized Solana transaction the user signs with their wallet (it creates — or reuses — the deterministic Swig and adds a sub-account). Sign this and round-trip the signed bytes to \`POST /v2/enroll\` as \`signedSolanaTransaction\`, instead of signing \`message\`. Carries a recent blockhash, so sign and submit promptly. - **`swigAccountId`** `string` — SVM B2B Model A (EVM-rooted) subaccount only: CAIP-10 of the parent Swig. The client needs it (plus \`agentAccountId\` and a fresh slot) to build the add-authority message the user signs with their EVM wallet, then submits to \`POST /v2/enroll\` with \`userSecp256k1PublicKey\` + \`currentSlot\`. - **`swigRoleId`** `integer` — SVM B2B subaccount path only: the Swig role id that will own the sub-account. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "message": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }, "agentAccountId": "eip155:0:0x1111111111111111111111111111111111111111", "accountIndex": "7", "accountType": "ECDSA", "flowId": "flow_01JWZEE2MF30KVRMRX53N88VA4", "solanaTransaction": "", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1, "reusedSwig": true, "swigAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj" } } ``` ### CreateEnrollSignatureData - **Type:**`object` * **`accountIndex` (required)** `string` — Reserved account index. Must be round-tripped to \`POST /v2/enroll\`. * **`agentAccountId` (required)** `string` — Pooled KMS agent as a chain-agnostic CAIP-10 identifier (\`eip155:0:\\`) that will operate the smart account post-enrollment. Must be round-tripped verbatim to \`POST /v2/enroll\`. * **`flowId` (required)** `string` — Opaque 24h reservation token. Must be round-tripped to \`POST /v2/enroll\` and also serves as the idempotency anchor there. * **`message` (required)** `object` — Discriminated union. ECDSA enrollment returns \`{ kind: "ecdsa", raw }\`; ERC-1271 enrollment returns \`{ kind: "typed-data", typedData }\`; SVM enrollment may return \`{ kind: "solana-message", text }\`. * **`accountType`** `string`, possible values: `"ECDSA", "ERC1271"` — EVM Kernel owner/validator configuration used to build \`message\`. Round-trip this to \`POST /v2/enroll\` when present. * **`depositAccountId`** `string` — SVM B2B subaccount path only: CAIP-10 of the Swig sub-account the user will deposit funds to once enrolled. Mirrors what \`POST /v2/enroll\` returns in \`smartAccounts\[].depositAccountId\`. * **`reusedSwig`** `boolean` — SVM B2B subaccount path only: \`true\` when an existing Swig PDA for this (tenant, user) is being reused (a subsequent vault), \`false\` when a new one will be created (the first vault). * **`solanaTransaction`** `string` — SVM B2B subaccount path only: the base64-serialized Solana transaction the user signs with their wallet (it creates — or reuses — the deterministic Swig and adds a sub-account). Sign this and round-trip the signed bytes to \`POST /v2/enroll\` as \`signedSolanaTransaction\`, instead of signing \`message\`. Carries a recent blockhash, so sign and submit promptly. * **`swigAccountId`** `string` — SVM B2B Model A (EVM-rooted) subaccount only: CAIP-10 of the parent Swig. The client needs it (plus \`agentAccountId\` and a fresh slot) to build the add-authority message the user signs with their EVM wallet, then submits to \`POST /v2/enroll\` with \`userSecp256k1PublicKey\` + \`currentSlot\`. * **`swigRoleId`** `integer` — SVM B2B subaccount path only: the Swig role id that will own the sub-account. **Example:** ```json { "message": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" }, "agentAccountId": "eip155:0:0x1111111111111111111111111111111111111111", "accountIndex": "7", "accountType": "ECDSA", "flowId": "flow_01JWZEE2MF30KVRMRX53N88VA4", "solanaTransaction": "", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1, "reusedSwig": true, "swigAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:7dHbWXmci3dT8UFYWYZweBLXgycu7Y3iL6trKn1Y7ARj" } ``` ### SessionKeyMessage - **Type:** Discriminated union. ECDSA enrollment returns `{ kind: "ecdsa", raw }`; ERC-1271 enrollment returns `{ kind: "typed-data", typedData }`; SVM enrollment may return `{ kind: "solana-message", text }`. **Example:** ### SessionKeyMessageEcdsa - **Type:**`object` * **`kind` (required)** `string`, possible values: `"ecdsa"` * **`raw` (required)** `string` — 32-byte hex hash. The user signs this via EIP-191 personal\_sign in their EVM wallet. **Example:** ```json { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" } ``` ### SessionKeyMessageSolana - **Type:**`object` * **`kind` (required)** `string`, possible values: `"solana-message"` * **`text` (required)** `string` — Human-readable canonical enrollment text. The Solana wallet displays this verbatim and signs the UTF-8 bytes via ed25519. **Example:** ```json { "kind": "solana-message", "text": "Glider — enroll Solana portfolio\n\nOwner: 7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU\nStrategy: 01JWZEE2MF30KVRMRX53N88VA4\nChain: 5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp\nSmart account: 5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9\nFlow: flow_01JWZEE2MF30KVRMRX53N88VA4\n\nDomain: glider:svm-enroll:solana:v1" } ``` ### SessionKeyMessageTypedData - **Type:**`object` * **`kind` (required)** `string`, possible values: `"typed-data"` * **`typedData` (required)** `object` — EIP-712 typed-data payload. The user signs this via their ERC-1271 smart wallet. - **`domain` (required)** `object` — EIP-712 domain. \`chainId\` is JSON-encoded as a number; signers may pass it directly to viem/wagmi. - **`chainId`** `integer` - **`name`** `string` - **`verifyingContract`** `string` - **`version`** `string` - **`message` (required)** `object` - **`primaryType` (required)** `string` - **`types` (required)** `object` **Example:** ```json { "kind": "typed-data", "typedData": { "domain": { "chainId": 1, "name": "", "verifyingContract": "", "version": "" }, "message": { "additionalProperty": "" }, "primaryType": "", "types": { "additionalProperty": [ { "name": "", "type": "" } ] } } } ``` ### SessionKeyTypedData - **Type:**`object` EIP-712 typed-data payload. The user signs this via their ERC-1271 smart wallet. - **`domain` (required)** `object` — EIP-712 domain. \`chainId\` is JSON-encoded as a number; signers may pass it directly to viem/wagmi. - **`chainId`** `integer` - **`name`** `string` - **`verifyingContract`** `string` - **`version`** `string` - **`message` (required)** `object` - **`primaryType` (required)** `string` - **`types` (required)** `object` **Example:** ```json { "domain": { "chainId": 1, "name": "", "verifyingContract": "", "version": "" }, "message": { "additionalProperty": "" }, "primaryType": "", "types": { "additionalProperty": [ { "name": "", "type": "" } ] } } ``` ### SessionKeyTypedDataField - **Type:**`object` * **`name` (required)** `string` * **`type` (required)** `string` **Example:** ```json { "name": "", "type": "" } ``` ### CreateEnrollSignatureRequest - **Type:**`object` * **`chainIds` (required)** `array` — Numeric chain ids the user wants smart accounts on. Must be a subset of the chains this deployment has RPCs configured for. **Items:** `integer` * **`ownerAccountId` (required)** `string` — End-user wallet as a CAIP-10 identifier. EVM: \`eip155:0:\\` (chain-agnostic per CAIP-10 §Abstract Account Addresses). Solana: \`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\` (CAIP-2 mainnet reference). * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`accountType`** `string`, possible values: `"ECDSA", "ERC1271"`, default: `"ECDSA"` — EVM Kernel owner/validator configuration. \`ECDSA\` uses the MultiChainECDSAValidator. \`ERC1271\` uses the Kernel SmartAccount validator and requires exactly one EVM chainId. **Example:** ```json { "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "chainIds": [ 1, 8453 ], "accountType": "ECDSA" } ``` ### CreateEnrollResponse - **Type:**`object` * **`data` (required)** `object` - **`portfolioId` (required)** `string` — Portfolio identifier - **`portfolioName` (required)** `string | null` — Integrator-provided display name for the portfolio. Null when the portfolio was created without one. - **`smartAccounts` (required)** `array` — Canonical SmartAccount objects, one per requested chain. Deterministic CREATE2 addresses. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. - **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ] } } ``` ### CreateEnrollData - **Type:**`object` * **`portfolioId` (required)** `string` — Portfolio identifier * **`portfolioName` (required)** `string | null` — Integrator-provided display name for the portfolio. Null when the portfolio was created without one. * **`smartAccounts` (required)** `array` — Canonical SmartAccount objects, one per requested chain. Deterministic CREATE2 addresses. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. * **`strategyId` (required)** `string` — Strategy identifier (ULID) **Example:** ```json { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ] } ``` ### SmartAccount - **Type:**`object` * **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. * **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. * **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. **Example:** ```json { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ``` ### CreateEnrollRequest - **Type:**`object` * **`accountIndex` (required)** `string` — Reserved account index as a decimal string. Must round-trip from \`POST /v2/enroll/signature\` into \`POST /v2/enroll\` so the server can recompute the session-key message. * **`agentAccountId` (required)** `string` — Pooled KMS agent CAIP-10 returned by \`POST /v2/enroll/signature\`. Must round-trip verbatim so the server can recompute the signable message. EVM (\`eip155:0:\\`) or Solana (\`solana:\:\\`). * **`chainIds` (required)** `array` — Numeric chain ids the user wants smart accounts on. Must be a subset of the chains this deployment has RPCs configured for. **Items:** `integer` * **`flowId` (required)** `string` — Opaque flow identifier. Valid for 24h. Also the idempotency anchor for \`POST /v2/enroll\`. * **`ownerAccountId` (required)** `string` — End-user wallet as a CAIP-10 identifier. EVM: \`eip155:0:\\`. Solana: \`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\`. * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`accountType`** `string`, possible values: `"ECDSA", "ERC1271"`, default: `"ECDSA"` — EVM Kernel owner/validator configuration. Must match the value used for \`POST /v2/enroll/signature\`. \`ERC1271\` requires exactly one EVM chainId. * **`currentSlot`** `string` — SVM B2B Model A subaccount: the Solana slot the client captured and bound \`signature\` to (decimal string). Submit promptly — Swig enforces a slot window. * **`ownerSignatureScheme`** `string`, possible values: `"eip191", "raw"` — SVM B2B Model A subaccount: how the wallet produced \`signature\` over the Swig payload hash. \`eip191\` (default) = \`personal\_sign\`; \`raw\` = bare secp256k1 over the hash. * **`portfolioName`** `string` — Integrator-provided display name for the portfolio. Trimmed server-side. Max 64 characters. Supports Unicode letters, digits, spaces, and - \_ . ' : ( ) & /. * **`signature`** `string` — Signature over the stage-1 message. Hex (EVM ECDSA / SVM Model A) or base58. Required for every path EXCEPT the SVM B2B subaccount path, which instead returns \`signedSolanaTransaction\`. * **`signedSolanaTransaction`** `string` — SVM B2B only: the base64-serialized, user-signed Solana transaction from \`POST /v2/enroll/signature\` (\`solanaTransaction\`). Provide this instead of \`signature\` for the SVM Model B subaccount enroll path. * **`userSecp256k1PublicKey`** `string` — SVM B2B Model A (EVM-rooted) subaccount: the user's secp256k1 public key (\`0x…\` hex). Required for the Model A subaccount path; its derived address must equal \`ownerAccountId\`'s address. Sent alongside \`signature\` (the slot-bound Swig authorization) and \`currentSlot\`. **Example:** ```json { "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "chainIds": [ 1, 8453 ], "accountType": "ECDSA", "accountIndex": "7", "agentAccountId": "eip155:0:0x1111111111111111111111111111111111111111", "signature": "0x9412d70d539f889ecec2d3152b68af758d689a4325a43b07811ee708814527c72256fc749d7fd3745a07f0aaa84813955050c461392d9b9ee1f80e106fac39e01b", "signedSolanaTransaction": "", "userSecp256k1PublicKey": "", "currentSlot": "299999999", "ownerSignatureScheme": "eip191", "flowId": "flow_01JWZEE2MF30KVRMRX53N88VA4", "portfolioName": "Alice's Portfolio" } ``` ### ListPortfoliosResponse - **Type:**`object` * **`data` (required)** `object` - **`portfolios` (required)** `array` **Items:** - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`ownerAccountId` (required)** `string | null` — End-user wallet as a chain-agnostic CAIP-10 identifier (\`eip155:0:\\`). Null only for legacy rows without an owner recorded. - **`portfolioId` (required)** `string` — Portfolio identifier - **`portfolioName` (required)** `string | null` — Integrator-provided display name for the portfolio. Null when the portfolio was created without one. - **`schedule` (required)** `object | null` — Rebalance schedule projection. Null when no rebalance schedule has been created for this portfolio. - **`frequency` (required)** `string | null`, possible values: `"hourly", "daily", "weekly", "monthly", null` — Resolved cadence enum. Null when the stored spec uses a non-standard \`intervalMs\` that does not map to the enum. - **`intervalMs` (required)** `integer | null` — Raw interval between rebalances in milliseconds - **`lastRebalanceAt` (required)** `string | null` — ISO 8601 timestamp for the most recent rebalance run (manual or scheduled). Null until the portfolio's first rebalance completes. - **`nextDueAt` (required)** `string | null` — ISO 8601 timestamp for the next scheduled rebalance. Use this to render 'next rebalance in …' UI or to decide whether to trigger a manual rebalance now. Null when the schedule is paused or no next tick has been computed yet. - **`status` (required)** `string`, possible values: `"active", "paused"` — Portfolio rebalance schedule status. \`active\` = scheduler will tick. \`paused\` = integrator has paused automation. - **`smartAccounts` (required)** `array` — Per-chain smart accounts owned by this portfolio. Each entry is the canonical \`SmartAccount\` object. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. - **`strategyDescription` (required)** `string | null` — Strategy description as set by the integrator at strategy creation time. Null when the strategy was created without one. - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`strategyName` (required)** `string` — Strategy display name at read time * **`nextCursor` (required)** `string | null` — Opaque cursor for the next page. Null when there are no more results. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolios": [ { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z" } ] }, "nextCursor": null } ``` ### PortfolioListItem - **Type:**`object` * **`createdAt` (required)** `string` — ISO 8601 creation timestamp * **`ownerAccountId` (required)** `string | null` — End-user wallet as a chain-agnostic CAIP-10 identifier (\`eip155:0:\\`). Null only for legacy rows without an owner recorded. * **`portfolioId` (required)** `string` — Portfolio identifier * **`portfolioName` (required)** `string | null` — Integrator-provided display name for the portfolio. Null when the portfolio was created without one. * **`schedule` (required)** `object | null` — Rebalance schedule projection. Null when no rebalance schedule has been created for this portfolio. - **`frequency` (required)** `string | null`, possible values: `"hourly", "daily", "weekly", "monthly", null` — Resolved cadence enum. Null when the stored spec uses a non-standard \`intervalMs\` that does not map to the enum. - **`intervalMs` (required)** `integer | null` — Raw interval between rebalances in milliseconds - **`lastRebalanceAt` (required)** `string | null` — ISO 8601 timestamp for the most recent rebalance run (manual or scheduled). Null until the portfolio's first rebalance completes. - **`nextDueAt` (required)** `string | null` — ISO 8601 timestamp for the next scheduled rebalance. Use this to render 'next rebalance in …' UI or to decide whether to trigger a manual rebalance now. Null when the schedule is paused or no next tick has been computed yet. - **`status` (required)** `string`, possible values: `"active", "paused"` — Portfolio rebalance schedule status. \`active\` = scheduler will tick. \`paused\` = integrator has paused automation. * **`smartAccounts` (required)** `array` — Per-chain smart accounts owned by this portfolio. Each entry is the canonical \`SmartAccount\` object. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. * **`strategyDescription` (required)** `string | null` — Strategy description as set by the integrator at strategy creation time. Null when the strategy was created without one. * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`strategyName` (required)** `string` — Strategy display name at read time **Example:** ```json { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z" } ``` ### PortfolioSchedule - **Type:**`[ "object", "null" ]` Rebalance schedule projection. Null when no rebalance schedule has been created for this portfolio. **Example:** ### GetPortfolioPositionsResponse - **Type:**`object` * **`data` (required)** `object` - **`assets` (required)** `array` **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier (fully chain-qualified). Covers ERC-20, SPL, and tokenized RWA assets — the same shape regardless of asset class. - **`balance` (required)** `string` — Human-readable token balance as a decimal string - **`balanceRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. - **`decimals` (required)** `integer` — Integer exponent used to convert \`balanceRaw\` to \`balance\`. The only non-string financial field on the v2 surface. - **`priceUsd` (required)** `string` — Unit price in USD as a decimal string, \`.toFixed(6)\` - **`smartAccountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`symbol` (required)** `string` — Asset symbol as reported by the upstream data provider (e.g. \`USDC\`, \`MORPHO\`, or a tokenized-equity ticker). - **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`fetchedAt` (required)** `string` — ISO 8601 timestamp at which balances + prices were read - **`inTransit` (required)** `object` — Open bridge value included in totalValueUsd but not yet visible as settled destination-chain asset rows. - **`items` (required)** `array` — Open bridge legs included in totalValueUsd but not yet reflected as destination-chain asset rows. **Items:** - **`amountRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. - **`destinationChainId` (required)** `integer` — Destination EVM chain id for the bridge leg. - **`sourceAssetId` (required)** `string` — Source asset identifier used for the in-transit bridge leg. This matches the source asset id used internally for the portfolio position. - **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`totalUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`portfolioId` (required)** `string` — Portfolio identifier - **`smartAccounts` (required)** `array` — Smart accounts configured for this portfolio. Always present regardless of whether live balances loaded. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. - **`totalValueUsd` (required)** `string` — Total USD value as a decimal string, \`.toFixed(6)\`. Sum of asset \`valueUsd\` for a single portfolio. - **`warnings` (required)** `array` — Non-fatal issues encountered while loading positions (e.g. a chain was unavailable, a price was missing). Empty array means a fully-healthy read. **Items:** - **`kind` (required)** `string`, possible values: `"MISSING_SMART_ACCOUNT", "RPC_ERROR", "MISSING_PRICE", "BLOCKLISTED_ASSET", "MISSING_ASSET", "IN_TRANSIT_READ_FAILED"` — Warning kind - **`message` (required)** `string` — Human-readable detail * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "totalValueUsd": "1500.500000", "inTransit": { "totalUsd": "1500.500000", "items": [ { "sourceAssetId": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913:8453", "destinationChainId": 42161, "amountRaw": "1500500000", "valueUsd": "1500.500000" } ] }, "fetchedAt": "2026-04-17T12:05:10.000Z", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "assets": [ { "assetId": "eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "smartAccountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "symbol": "USDC", "decimals": 6, "balance": "1500.500000", "balanceRaw": "1500500000", "priceUsd": "1.000000", "valueUsd": "1500.500000" } ], "warnings": [ { "kind": "RPC_ERROR", "message": "chain 1 RPC timeout" } ] } } ``` ### PortfolioPositionsData - **Type:**`object` * **`assets` (required)** `array` **Items:** - **`assetId` (required)** `string` — CAIP-19 asset identifier (fully chain-qualified). Covers ERC-20, SPL, and tokenized RWA assets — the same shape regardless of asset class. - **`balance` (required)** `string` — Human-readable token balance as a decimal string - **`balanceRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. - **`decimals` (required)** `integer` — Integer exponent used to convert \`balanceRaw\` to \`balance\`. The only non-string financial field on the v2 surface. - **`priceUsd` (required)** `string` — Unit price in USD as a decimal string, \`.toFixed(6)\` - **`smartAccountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`symbol` (required)** `string` — Asset symbol as reported by the upstream data provider (e.g. \`USDC\`, \`MORPHO\`, or a tokenized-equity ticker). - **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` * **`fetchedAt` (required)** `string` — ISO 8601 timestamp at which balances + prices were read * **`inTransit` (required)** `object` — Open bridge value included in totalValueUsd but not yet visible as settled destination-chain asset rows. - **`items` (required)** `array` — Open bridge legs included in totalValueUsd but not yet reflected as destination-chain asset rows. **Items:** - **`amountRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. - **`destinationChainId` (required)** `integer` — Destination EVM chain id for the bridge leg. - **`sourceAssetId` (required)** `string` — Source asset identifier used for the in-transit bridge leg. This matches the source asset id used internally for the portfolio position. - **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`totalUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` * **`portfolioId` (required)** `string` — Portfolio identifier * **`smartAccounts` (required)** `array` — Smart accounts configured for this portfolio. Always present regardless of whether live balances loaded. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. * **`totalValueUsd` (required)** `string` — Total USD value as a decimal string, \`.toFixed(6)\`. Sum of asset \`valueUsd\` for a single portfolio. * **`warnings` (required)** `array` — Non-fatal issues encountered while loading positions (e.g. a chain was unavailable, a price was missing). Empty array means a fully-healthy read. **Items:** - **`kind` (required)** `string`, possible values: `"MISSING_SMART_ACCOUNT", "RPC_ERROR", "MISSING_PRICE", "BLOCKLISTED_ASSET", "MISSING_ASSET", "IN_TRANSIT_READ_FAILED"` — Warning kind - **`message` (required)** `string` — Human-readable detail **Example:** ```json { "portfolioId": "a1b2c3d4", "totalValueUsd": "1500.500000", "inTransit": { "totalUsd": "1500.500000", "items": [ { "sourceAssetId": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913:8453", "destinationChainId": 42161, "amountRaw": "1500500000", "valueUsd": "1500.500000" } ] }, "fetchedAt": "2026-04-17T12:05:10.000Z", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "assets": [ { "assetId": "eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "smartAccountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "symbol": "USDC", "decimals": 6, "balance": "1500.500000", "balanceRaw": "1500500000", "priceUsd": "1.000000", "valueUsd": "1500.500000" } ], "warnings": [ { "kind": "RPC_ERROR", "message": "chain 1 RPC timeout" } ] } ``` ### PortfolioInTransit - **Type:**`object` Open bridge value included in totalValueUsd but not yet visible as settled destination-chain asset rows. - **`items` (required)** `array` — Open bridge legs included in totalValueUsd but not yet reflected as destination-chain asset rows. **Items:** - **`amountRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. - **`destinationChainId` (required)** `integer` — Destination EVM chain id for the bridge leg. - **`sourceAssetId` (required)** `string` — Source asset identifier used for the in-transit bridge leg. This matches the source asset id used internally for the portfolio position. - **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` - **`totalUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` **Example:** ```json { "totalUsd": "1500.500000", "items": [ { "sourceAssetId": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913:8453", "destinationChainId": 42161, "amountRaw": "1500500000", "valueUsd": "1500.500000" } ] } ``` ### PortfolioInTransitItem - **Type:**`object` * **`amountRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. * **`destinationChainId` (required)** `integer` — Destination EVM chain id for the bridge leg. * **`sourceAssetId` (required)** `string` — Source asset identifier used for the in-transit bridge leg. This matches the source asset id used internally for the portfolio position. * **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` **Example:** ```json { "sourceAssetId": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913:8453", "destinationChainId": 42161, "amountRaw": "1500500000", "valueUsd": "1500.500000" } ``` ### PortfolioAsset - **Type:**`object` * **`assetId` (required)** `string` — CAIP-19 asset identifier (fully chain-qualified). Covers ERC-20, SPL, and tokenized RWA assets — the same shape regardless of asset class. * **`balance` (required)** `string` — Human-readable token balance as a decimal string * **`balanceRaw` (required)** `string` — Raw integer token balance as a decimal string (no decimals applied). The on-chain \`uint256\` amount before dividing by \`10^decimals\`. * **`decimals` (required)** `integer` — Integer exponent used to convert \`balanceRaw\` to \`balance\`. The only non-string financial field on the v2 surface. * **`priceUsd` (required)** `string` — Unit price in USD as a decimal string, \`.toFixed(6)\` * **`smartAccountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. * **`symbol` (required)** `string` — Asset symbol as reported by the upstream data provider (e.g. \`USDC\`, \`MORPHO\`, or a tokenized-equity ticker). * **`valueUsd` (required)** `string` — USD value as a decimal string, \`.toFixed(6)\` **Example:** ```json { "assetId": "eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913", "smartAccountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "symbol": "USDC", "decimals": 6, "balance": "1500.500000", "balanceRaw": "1500500000", "priceUsd": "1.000000", "valueUsd": "1500.500000" } ``` ### PortfolioPositionWarning - **Type:**`object` * **`kind` (required)** `string`, possible values: `"MISSING_SMART_ACCOUNT", "RPC_ERROR", "MISSING_PRICE", "BLOCKLISTED_ASSET", "MISSING_ASSET", "IN_TRANSIT_READ_FAILED"` — Warning kind * **`message` (required)** `string` — Human-readable detail **Example:** ```json { "kind": "RPC_ERROR", "message": "chain 1 RPC timeout" } ``` ### GetPortfolioSectorExposureResponse - **Type:**`object` * **`data` (required)** `object` - **`asOfDate` (required)** `string` — ISO 8601 timestamp (UTC) - **`classifiedMarketValueUsd` (required)** `string` - **`diagnostics` (required)** `object` - **`lowConfidencePositions` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string` - **`assetId` (required)** `string` - **`confidence` (required)** `integer` - **`displaySector` (required)** `string`, possible values: `"Technology", "Communication Services", "Consumer Cyclical", "Consumer Defensive", "Financial Services", "Healthcare", "Industrials", "Basic Materials", "Energy", "Utilities", "Real Estate", "Unclassified"` - **`marketValueUsd` (required)** `string` - **`source` (required)** `string`, possible values: `"manual_override", "financedatabase_share_class_figi", "financedatabase_composite_figi", "financedatabase_isin", "financedatabase_cusip", "financedatabase_cik", "financedatabase_symbol_exchange", "massive_sic_ff48", "massive_sic_direct", "unclassified"` - **`symbol` (required)** `string | null` - **`unclassifiedPositions` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`assetId` (required)** `string` - **`marketValueUsd` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`unsupportedPositions` (required)** `array` **Items:** - **`assetId` (required)** `string` - **`marketValueUsd` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`portfolioId` (required)** `string` — Portfolio identifier - **`rows` (required)** `array` **Items:** - **`classifiedPositionCount` (required)** `integer` - **`displaySector` (required)** `string`, possible values: `"Technology", "Communication Services", "Consumer Cyclical", "Consumer Defensive", "Financial Services", "Healthcare", "Industrials", "Basic Materials", "Energy", "Utilities", "Real Estate", "Unclassified"` - **`marketValueUsd` (required)** `string` - **`primarySources` (required)** `array` **Items:** - **`count` (required)** `integer` - **`marketValueUsd` (required)** `string` - **`source` (required)** `string`, possible values: `"manual_override", "financedatabase_share_class_figi", "financedatabase_composite_figi", "financedatabase_isin", "financedatabase_cusip", "financedatabase_cik", "financedatabase_symbol_exchange", "massive_sic_ff48", "massive_sic_direct", "unclassified"` - **`totalPositionCount` (required)** `integer` - **`weight` (required)** `string` - **`taxonomy` (required)** `string`, possible values: `"internal_display_sector_v1"` - **`totalMarketValueUsd` (required)** `string` - **`unclassifiedMarketValueUsd` (required)** `string` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "asOfDate": "2026-04-17T12:00:00.000Z", "taxonomy": "internal_display_sector_v1", "totalMarketValueUsd": "", "classifiedMarketValueUsd": "", "unclassifiedMarketValueUsd": "", "rows": [ { "displaySector": "Technology", "marketValueUsd": "", "weight": "", "classifiedPositionCount": 0, "totalPositionCount": 0, "primarySources": [ { "source": "manual_override", "count": 0, "marketValueUsd": "" } ] } ], "diagnostics": { "unsupportedPositions": [ { "assetId": "", "symbol": null, "reason": "", "marketValueUsd": "" } ], "unclassifiedPositions": [ { "assetId": "", "symbol": null, "assetCanonicalId": null, "reason": "", "marketValueUsd": "" } ], "lowConfidencePositions": [ { "assetId": "", "symbol": null, "assetCanonicalId": "", "displaySector": "Technology", "source": "manual_override", "confidence": 0, "marketValueUsd": "" } ] } } } ``` ### PortfolioSectorExposureData - **Type:**`object` * **`asOfDate` (required)** `string` — ISO 8601 timestamp (UTC) * **`classifiedMarketValueUsd` (required)** `string` * **`diagnostics` (required)** `object` - **`lowConfidencePositions` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string` - **`assetId` (required)** `string` - **`confidence` (required)** `integer` - **`displaySector` (required)** `string`, possible values: `"Technology", "Communication Services", "Consumer Cyclical", "Consumer Defensive", "Financial Services", "Healthcare", "Industrials", "Basic Materials", "Energy", "Utilities", "Real Estate", "Unclassified"` - **`marketValueUsd` (required)** `string` - **`source` (required)** `string`, possible values: `"manual_override", "financedatabase_share_class_figi", "financedatabase_composite_figi", "financedatabase_isin", "financedatabase_cusip", "financedatabase_cik", "financedatabase_symbol_exchange", "massive_sic_ff48", "massive_sic_direct", "unclassified"` - **`symbol` (required)** `string | null` - **`unclassifiedPositions` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`assetId` (required)** `string` - **`marketValueUsd` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`unsupportedPositions` (required)** `array` **Items:** - **`assetId` (required)** `string` - **`marketValueUsd` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` * **`portfolioId` (required)** `string` — Portfolio identifier * **`rows` (required)** `array` **Items:** - **`classifiedPositionCount` (required)** `integer` - **`displaySector` (required)** `string`, possible values: `"Technology", "Communication Services", "Consumer Cyclical", "Consumer Defensive", "Financial Services", "Healthcare", "Industrials", "Basic Materials", "Energy", "Utilities", "Real Estate", "Unclassified"` - **`marketValueUsd` (required)** `string` - **`primarySources` (required)** `array` **Items:** - **`count` (required)** `integer` - **`marketValueUsd` (required)** `string` - **`source` (required)** `string`, possible values: `"manual_override", "financedatabase_share_class_figi", "financedatabase_composite_figi", "financedatabase_isin", "financedatabase_cusip", "financedatabase_cik", "financedatabase_symbol_exchange", "massive_sic_ff48", "massive_sic_direct", "unclassified"` - **`totalPositionCount` (required)** `integer` - **`weight` (required)** `string` * **`taxonomy` (required)** `string`, possible values: `"internal_display_sector_v1"` * **`totalMarketValueUsd` (required)** `string` * **`unclassifiedMarketValueUsd` (required)** `string` **Example:** ```json { "portfolioId": "a1b2c3d4", "asOfDate": "2026-04-17T12:00:00.000Z", "taxonomy": "internal_display_sector_v1", "totalMarketValueUsd": "", "classifiedMarketValueUsd": "", "unclassifiedMarketValueUsd": "", "rows": [ { "displaySector": "Technology", "marketValueUsd": "", "weight": "", "classifiedPositionCount": 0, "totalPositionCount": 0, "primarySources": [ { "source": "manual_override", "count": 0, "marketValueUsd": "" } ] } ], "diagnostics": { "unsupportedPositions": [ { "assetId": "", "symbol": null, "reason": "", "marketValueUsd": "" } ], "unclassifiedPositions": [ { "assetId": "", "symbol": null, "assetCanonicalId": null, "reason": "", "marketValueUsd": "" } ], "lowConfidencePositions": [ { "assetId": "", "symbol": null, "assetCanonicalId": "", "displaySector": "Technology", "source": "manual_override", "confidence": 0, "marketValueUsd": "" } ] } } ``` ### GetPortfolioPerformanceResponse - **Type:**`object` * **`data` (required)** `object` - **`meta` (required)** `object` - **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. - **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. - **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. - **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. - **`points` (required)** `array` — Daily performance series for the portfolio using \`meta.method\`, with cash flows reported by UTC day. **Items:** - **`cashFlowUsd` (required)** `string` — Net external cash flow aggregated into this UTC day, denominated in USD. Signed: positive on net-deposit days, negative on net-withdrawal days, \`0\` when flows cancel or none occurred. - **`date` (required)** `string` — UTC calendar date for this point. - **`percentChange` (required)** `string | null` — Cumulative return at this point under \`meta.method\` (\`TWR\` compounded from the first returned point; \`MWR\` money-weighted, reflecting deposits and withdrawals). \`null\` when a return is unavailable for this point. - **`valueUsd` (required)** `string` — Portfolio value for this UTC day, denominated in USD. For today, this may reflect the latest live value. - **`isLive`** `boolean` — True when this daily point includes the latest live portfolio value. - **`portfolioId` (required)** `string` — Portfolio identifier - **`strategyId` (required)** `string` — Strategy identifier (ULID) - **`summary`** `object` — Aggregate stats derived from the points array. Omitted when the curve has fewer than two points. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "meta": { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" }, "points": [ { "date": "2026-04-30", "percentChange": "4.1234", "valueUsd": "1523.450000", "cashFlowUsd": "100.000000", "isLive": true } ], "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } } ``` ### PortfolioPerformance - **Type:**`object` * **`meta` (required)** `object` - **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. - **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. - **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. - **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. * **`points` (required)** `array` — Daily performance series for the portfolio using \`meta.method\`, with cash flows reported by UTC day. **Items:** - **`cashFlowUsd` (required)** `string` — Net external cash flow aggregated into this UTC day, denominated in USD. Signed: positive on net-deposit days, negative on net-withdrawal days, \`0\` when flows cancel or none occurred. - **`date` (required)** `string` — UTC calendar date for this point. - **`percentChange` (required)** `string | null` — Cumulative return at this point under \`meta.method\` (\`TWR\` compounded from the first returned point; \`MWR\` money-weighted, reflecting deposits and withdrawals). \`null\` when a return is unavailable for this point. - **`valueUsd` (required)** `string` — Portfolio value for this UTC day, denominated in USD. For today, this may reflect the latest live value. - **`isLive`** `boolean` — True when this daily point includes the latest live portfolio value. * **`portfolioId` (required)** `string` — Portfolio identifier * **`strategyId` (required)** `string` — Strategy identifier (ULID) * **`summary`** `object` — Aggregate stats derived from the points array. Omitted when the curve has fewer than two points. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. **Example:** ```json { "portfolioId": "a1b2c3d4", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "meta": { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" }, "points": [ { "date": "2026-04-30", "percentChange": "4.1234", "valueUsd": "1523.450000", "cashFlowUsd": "100.000000", "isLive": true } ], "summary": { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } } ``` ### PortfolioPerformanceMeta - **Type:**`object` * **`asOf` (required)** `string`, format: `date-time` — Wall-clock the curve was computed at, in ISO 8601. * **`currency` (required)** `string`, possible values: `"USD"` — Currency for any monetary fields. Currently always USD. * **`method` (required)** `string`, possible values: `"TWR", "MWR"` — Return calculation methodology. * **`resolution` (required)** `string`, possible values: `"1d"` — Performance points are reported by UTC day. **Example:** ```json { "method": "MWR", "currency": "USD", "resolution": "1d", "asOf": "2026-05-05T16:00:00.000Z" } ``` ### PortfolioPerformancePoint - **Type:**`object` * **`cashFlowUsd` (required)** `string` — Net external cash flow aggregated into this UTC day, denominated in USD. Signed: positive on net-deposit days, negative on net-withdrawal days, \`0\` when flows cancel or none occurred. * **`date` (required)** `string` — UTC calendar date for this point. * **`percentChange` (required)** `string | null` — Cumulative return at this point under \`meta.method\` (\`TWR\` compounded from the first returned point; \`MWR\` money-weighted, reflecting deposits and withdrawals). \`null\` when a return is unavailable for this point. * **`valueUsd` (required)** `string` — Portfolio value for this UTC day, denominated in USD. For today, this may reflect the latest live value. * **`isLive`** `boolean` — True when this daily point includes the latest live portfolio value. **Example:** ```json { "date": "2026-04-30", "percentChange": "4.1234", "valueUsd": "1523.450000", "cashFlowUsd": "100.000000", "isLive": true } ``` ### PortfolioPerformanceSummary - **Type:**`object` Aggregate stats derived from the points array. Omitted when the curve has fewer than two points. - **`windows` (required)** `array` — Windowed lookbacks ordered shortest → longest. Windows that predate the curve are omitted. **Items:** - **`percentChange` (required)** `string` — Percent change from \`since\` to the last point using the response's \`meta.method\`. - **`since` (required)** `string` — UTC calendar date the return is anchored on. - **`window` (required)** `string`, possible values: `"1d", "1w", "1m", "3m", "6m", "12m"` — Lookback window key. **Example:** ```json { "windows": [ { "window": "1w", "percentChange": "1.7812", "since": "2026-04-23" } ] } ``` ### StartPortfolioResponse - **Type:**`object` * **`data` (required)** `object` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ### PortfolioDetail - **Type:** **Example:** ### StopPortfolioResponse - **Type:**`object` * **`data` (required)** `object` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ### TriggerRebalanceResponse - **Type:**`object` * **`data` (required)** `object` - **`operationId` (required)** `string` — Operation identifier to poll with \`GET /v2/portfolios/{portfolioId}/operations/{operationId}\` for rebalance status. - **`submittedAt` (required)** `string` — ISO 8601 timestamp when the rebalance was accepted * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "operationId": "rebalance:a1b2c3d4:a1b2c3d4%3Amanual%3Areq_01JWZEE2MF30KVRMRX53N88VA4", "submittedAt": "2026-04-17T12:00:00.000Z" } } ``` ### TriggerRebalanceData - **Type:**`object` * **`operationId` (required)** `string` — Operation identifier to poll with \`GET /v2/portfolios/{portfolioId}/operations/{operationId}\` for rebalance status. * **`submittedAt` (required)** `string` — ISO 8601 timestamp when the rebalance was accepted **Example:** ```json { "operationId": "rebalance:a1b2c3d4:a1b2c3d4%3Amanual%3Areq_01JWZEE2MF30KVRMRX53N88VA4", "submittedAt": "2026-04-17T12:00:00.000Z" } ``` ### WithdrawSignatureResponse - **Type:**`object` * **`data` (required)** `object` - **`authorizationId` (required)** `string` — Opaque 32-byte hex nonce. Use as the idempotency anchor for stage 2 retries of the same signed authorization. - **`expiresAt` (required)** `string` — ISO 8601 timestamp after which the authorization cannot be submitted. Matches the signed \`expiresAt\` (Unix seconds). - **`authorization`** `object` — Solana portfolios only. The off-chain authorization to sign with the portfolio owner's wallet — \`kind: "ecdsa"\` (EVM-rooted Model A; sign \`raw\` via EIP-191) or \`kind: "solana-message"\` (Solana-rooted Model B; sign \`text\` via ed25519). Echo \`authorization.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. - **`typedData`** `object` — EVM portfolios only. Full EIP-712 typed-data object. Pass directly to \`signTypedData(...)\` in the user's wallet; echo \`typedData.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. - **`domain` (required)** `object` - **`chainId` (required)** `integer` — The EVM chain id the recipient + assets live on. Required by ERC-1271 smart-wallet verifiers that re-hash typed-data using the wallet's own chainId. - **`name` (required)** `string`, possible values: `"Glider Withdrawal Authorization"` - **`verifyingContract` (required)** `string` — The smart account address being debited (bare EVM address, not a CAIP-10). Binds the signature to this specific smart account deployment. Documented exception to the \`\*AccountId\` rule — dictated by EIP-712. - **`version` (required)** `string`, possible values: `"1", "2"` - **`message` (required)** `object` - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units to withdraw as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, possible values: `true` — Present (and \`true\`) only on a liquidation (version-"2" message); the \`assets\` are swapped to \`settlementAssetId\` and delivered to the recipient. Omitted for plain transfers. Echoed verbatim from stage 1. - **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as the recipient and assets: configured USDC or USDT for an EVM liquidation, or USDC for a Solana liquidation. Cross-chain settlement is not supported. Present only on a liquidation (version-"2" message), omitted for plain transfers. Echoed verbatim from stage 1. - **`primaryType` (required)** `string`, possible values: `"Withdrawal"` - **`types` (required)** `object` - **`Withdrawal` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` - **`WithdrawalAsset` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "authorizationId": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": "2026-04-17T12:10:00.000Z", "typedData": { "primaryType": "Withdrawal", "domain": { "name": "Glider Withdrawal Authorization", "version": "1", "chainId": 1, "verifyingContract": "0x2222222222222222222222222222222222222222" }, "types": { "Withdrawal": [ { "name": "", "type": "" } ], "WithdrawalAsset": [ { "name": "", "type": "" } ] }, "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } }, "authorization": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "" } } } } ``` ### WithdrawSignatureData - **Type:**`object` * **`authorizationId` (required)** `string` — Opaque 32-byte hex nonce. Use as the idempotency anchor for stage 2 retries of the same signed authorization. * **`expiresAt` (required)** `string` — ISO 8601 timestamp after which the authorization cannot be submitted. Matches the signed \`expiresAt\` (Unix seconds). * **`authorization`** `object` — Solana portfolios only. The off-chain authorization to sign with the portfolio owner's wallet — \`kind: "ecdsa"\` (EVM-rooted Model A; sign \`raw\` via EIP-191) or \`kind: "solana-message"\` (Solana-rooted Model B; sign \`text\` via ed25519). Echo \`authorization.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. * **`typedData`** `object` — EVM portfolios only. Full EIP-712 typed-data object. Pass directly to \`signTypedData(...)\` in the user's wallet; echo \`typedData.message\` back as \`body.message\` on \`POST /v2/portfolios/{portfolioId}/withdraw\`. - **`domain` (required)** `object` - **`chainId` (required)** `integer` — The EVM chain id the recipient + assets live on. Required by ERC-1271 smart-wallet verifiers that re-hash typed-data using the wallet's own chainId. - **`name` (required)** `string`, possible values: `"Glider Withdrawal Authorization"` - **`verifyingContract` (required)** `string` — The smart account address being debited (bare EVM address, not a CAIP-10). Binds the signature to this specific smart account deployment. Documented exception to the \`\*AccountId\` rule — dictated by EIP-712. - **`version` (required)** `string`, possible values: `"1", "2"` - **`message` (required)** `object` - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units to withdraw as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, possible values: `true` — Present (and \`true\`) only on a liquidation (version-"2" message); the \`assets\` are swapped to \`settlementAssetId\` and delivered to the recipient. Omitted for plain transfers. Echoed verbatim from stage 1. - **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as the recipient and assets: configured USDC or USDT for an EVM liquidation, or USDC for a Solana liquidation. Cross-chain settlement is not supported. Present only on a liquidation (version-"2" message), omitted for plain transfers. Echoed verbatim from stage 1. - **`primaryType` (required)** `string`, possible values: `"Withdrawal"` - **`types` (required)** `object` - **`Withdrawal` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` - **`WithdrawalAsset` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` **Example:** ```json { "authorizationId": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": "2026-04-17T12:10:00.000Z", "typedData": { "primaryType": "Withdrawal", "domain": { "name": "Glider Withdrawal Authorization", "version": "1", "chainId": 1, "verifyingContract": "0x2222222222222222222222222222222222222222" }, "types": { "Withdrawal": [ { "name": "", "type": "" } ], "WithdrawalAsset": [ { "name": "", "type": "" } ] }, "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } }, "authorization": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "" } } } ``` ### WithdrawEip712TypedData - **Type:**`object` EVM portfolios only. Full EIP-712 typed-data object. Pass directly to `signTypedData(...)` in the user's wallet; echo `typedData.message` back as `body.message` on `POST /v2/portfolios/{portfolioId}/withdraw`. - **`domain` (required)** `object` - **`chainId` (required)** `integer` — The EVM chain id the recipient + assets live on. Required by ERC-1271 smart-wallet verifiers that re-hash typed-data using the wallet's own chainId. - **`name` (required)** `string`, possible values: `"Glider Withdrawal Authorization"` - **`verifyingContract` (required)** `string` — The smart account address being debited (bare EVM address, not a CAIP-10). Binds the signature to this specific smart account deployment. Documented exception to the \`\*AccountId\` rule — dictated by EIP-712. - **`version` (required)** `string`, possible values: `"1", "2"` - **`message` (required)** `object` - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units to withdraw as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` — CAIP-19 asset identifier - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, possible values: `true` — Present (and \`true\`) only on a liquidation (version-"2" message); the \`assets\` are swapped to \`settlementAssetId\` and delivered to the recipient. Omitted for plain transfers. Echoed verbatim from stage 1. - **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as the recipient and assets: configured USDC or USDT for an EVM liquidation, or USDC for a Solana liquidation. Cross-chain settlement is not supported. Present only on a liquidation (version-"2" message), omitted for plain transfers. Echoed verbatim from stage 1. - **`primaryType` (required)** `string`, possible values: `"Withdrawal"` - **`types` (required)** `object` - **`Withdrawal` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` - **`WithdrawalAsset` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` **Example:** ```json { "primaryType": "Withdrawal", "domain": { "name": "Glider Withdrawal Authorization", "version": "1", "chainId": 1, "verifyingContract": "0x2222222222222222222222222222222222222222" }, "types": { "Withdrawal": [ { "name": "", "type": "" } ], "WithdrawalAsset": [ { "name": "", "type": "" } ] }, "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } } ``` ### WithdrawEip712Domain - **Type:**`object` * **`chainId` (required)** `integer` — The EVM chain id the recipient + assets live on. Required by ERC-1271 smart-wallet verifiers that re-hash typed-data using the wallet's own chainId. * **`name` (required)** `string`, possible values: `"Glider Withdrawal Authorization"` * **`verifyingContract` (required)** `string` — The smart account address being debited (bare EVM address, not a CAIP-10). Binds the signature to this specific smart account deployment. Documented exception to the \`\*AccountId\` rule — dictated by EIP-712. * **`version` (required)** `string`, possible values: `"1", "2"` **Example:** ```json { "name": "Glider Withdrawal Authorization", "version": "1", "chainId": 1, "verifyingContract": "0x2222222222222222222222222222222222222222" } ``` ### WithdrawEip712Types - **Type:**`object` * **`Withdrawal` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` * **`WithdrawalAsset` (required)** `array` **Items:** - **`name` (required)** `string` - **`type` (required)** `string` **Example:** ```json { "Withdrawal": [ { "name": "", "type": "" } ], "WithdrawalAsset": [ { "name": "", "type": "" } ] } ``` ### WithdrawEip712Field - **Type:**`object` * **`name` (required)** `string` * **`type` (required)** `string` **Example:** ```json { "name": "", "type": "" } ``` ### WithdrawEip712MessageBody - **Type:**`object` * **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units to withdraw as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` — CAIP-19 asset identifier * **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. * **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string * **`portfolioId` (required)** `string` * **`recipientAccountId` (required)** `string` * **`liquidate`** `boolean`, possible values: `true` — Present (and \`true\`) only on a liquidation (version-"2" message); the \`assets\` are swapped to \`settlementAssetId\` and delivered to the recipient. Omitted for plain transfers. Echoed verbatim from stage 1. * **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as the recipient and assets: configured USDC or USDT for an EVM liquidation, or USDC for a Solana liquidation. Cross-chain settlement is not supported. Present only on a liquidation (version-"2" message), omitted for plain transfers. Echoed verbatim from stage 1. **Example:** ```json { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } ``` ### WithdrawEip712Asset - **Type:**`object` * **`amountRaw` (required)** `string` — Atomic (raw) units to withdraw as a decimal string. Positive integer, no leading zeros. * **`assetId` (required)** `string` — CAIP-19 asset identifier **Example:** ```json { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ``` ### SolanaWithdrawAuthorization - **Type:** Solana portfolios only. The off-chain authorization to sign with the portfolio owner's wallet — `kind: "ecdsa"` (EVM-rooted Model A; sign `raw` via EIP-191) or `kind: "solana-message"` (Solana-rooted Model B; sign `text` via ed25519). Echo `authorization.message` back as `body.message` on `POST /v2/portfolios/{portfolioId}/withdraw`. **Example:** ### SolanaWithdrawAuthorizationMessage - **Type:**`object` * **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) unit amount as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` * **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. * **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string * **`portfolioId` (required)** `string` * **`recipientAccountId` (required)** `string` * **`liquidate`** `boolean` — Present (\`true\`) on liquidate-all authorizations: the assets are swapped to \`settlementAssetId\` and the proceeds delivered to the recipient. Absent for plain transfers. * **`settlementAssetId`** `string` — Liquidations only. CAIP-19 of the settlement asset (USDC on Solana) the assets are swapped to. Echo verbatim on stage 2. **Example:** ```json { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": true, "settlementAssetId": "" } ``` ### WithdrawSignatureRequest - **Type:**`object` * **`assets` (required)** `array` — Assets to withdraw. All entries must be on the same chain as \`recipientAccountId\`. **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) units as a decimal string. Read the live balance from \`GET /v2/portfolios/{portfolioId}/positions\` and echo \`balanceRaw\` for a full withdrawal. Must be a positive integer (no leading zeros). - **`assetId` (required)** `string` — CAIP-19 asset identifier. Chain is derived from the \`eip155:\\` prefix. * **`recipientAccountId` (required)** `string` — CAIP-10 recipient on the withdrawal chain. Every \`assets\[].assetId\` and, when \`liquidate\` is true, \`settlementAssetId\` must reference this same chain. Cross-chain delivery and bridging are not supported. EVM: \`eip155:\:\\`. Solana: \`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\`. One request authorizes one recipient on one chain; multi-chain withdrawals require separate authorizations. * **`liquidate`** `boolean`, default: `false` — When true, the listed \`assets\` are swapped to the \`settlementAssetId\` settlement asset (USDC by default) and delivered to \`recipientAccountId\`. Assets whose value is below the tenant swap threshold are skipped and stay in the vault. When false (default), each asset is transferred as-is. * **`settlementAssetId`** `string` — Liquidation only (\`liquidate: true\`). CAIP-19 settlement asset on the same chain as \`recipientAccountId\` and every \`assets\[].assetId\`. For an EVM withdrawal, use configured USDC or USDT on that EVM chain. For a Solana withdrawal, use Solana USDC. Omit to default to USDC on the withdrawal chain. This field does not select a different destination chain or enable bridging. Rejected when \`liquidate\` is false. **Example:** ```json { "recipientAccountId": "eip155:8453:0x4444444444444444444444444444444444444444", "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ], "liquidate": false, "settlementAssetId": "eip155:56/erc20:0x55d398326f99059fF775485246999027B3197955" } ``` ### WithdrawalAsset - **Type:**`object` * **`amountRaw` (required)** `string` — Atomic (raw) units as a decimal string. Read the live balance from \`GET /v2/portfolios/{portfolioId}/positions\` and echo \`balanceRaw\` for a full withdrawal. Must be a positive integer (no leading zeros). * **`assetId` (required)** `string` — CAIP-19 asset identifier. Chain is derived from the \`eip155:\\` prefix. **Example:** ```json { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "amountRaw": "1000500000" } ``` ### WithdrawResponse - **Type:**`object` * **`data` (required)** `object` - **`operationId` (required)** `string` — Operation identifier to poll with \`GET /v2/portfolios/{portfolioId}/operations/{operationId}\` for onchain confirmation. - **`submittedAt` (required)** `string` — ISO 8601 timestamp when the withdrawal was dispatched * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4", "submittedAt": "2026-04-17T12:05:00.000Z" } } ``` ### WithdrawData - **Type:**`object` * **`operationId` (required)** `string` — Operation identifier to poll with \`GET /v2/portfolios/{portfolioId}/operations/{operationId}\` for onchain confirmation. * **`submittedAt` (required)** `string` — ISO 8601 timestamp when the withdrawal was dispatched **Example:** ```json { "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4", "submittedAt": "2026-04-17T12:05:00.000Z" } ``` ### WithdrawRequest - **Type:**`object` * **`message` (required)** `object` — The inner \`message\` body from the stage-1 response, echoed verbatim — \`typedData.message\` (EVM) or \`authorization.message\` (Solana). The server reconstructs the signed payload and verifies the signature against the portfolio owner. - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) unit amount as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, default: `false` — Echoed verbatim from stage 1. When true, the authorization swaps \`assets\` to \`settlementAssetId\` and delivers it to the recipient. Defaults to false if omitted. - **`settlementAssetId`** `string` — Echoed verbatim from stage 1. CAIP-19 settlement asset on the same chain as \`recipientAccountId\` and every \`assets\[].assetId\`: configured USDC or USDT for an EVM withdrawal, or USDC for a Solana withdrawal. It does not enable cross-chain delivery or bridging. Omitted for plain transfers. * **`signature` (required)** `string` — User's signature over the stage-1 authorization. EVM = \`0x\`-hex EIP-712/EIP-191 (ECDSA EOA or ERC-1271). Solana Model A (EVM-rooted) = \`0x\`-hex EIP-191; Model B (Solana-rooted) = base58 ed25519. **Example:** ```json { "message": { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": false, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" }, "signature": "0x9412d70d539f889ecec2d3152b68af758d689a4325a43b07811ee708814527c72256fc749d7fd3745a07f0aaa84813955050c461392d9b9ee1f80e106fac39e01b" } ``` ### WithdrawMessage - **Type:**`object` The inner `message` body from the stage-1 response, echoed verbatim — `typedData.message` (EVM) or `authorization.message` (Solana). The server reconstructs the signed payload and verifies the signature against the portfolio owner. - **`assets` (required)** `array` **Items:** - **`amountRaw` (required)** `string` — Atomic (raw) unit amount as a decimal string. Positive integer, no leading zeros. - **`assetId` (required)** `string` - **`expiresAt` (required)** `integer` — Expiry as Unix seconds. Used only inside EIP-712 signed payloads — outside that boundary v2 uses ISO-8601 strings. - **`nonce` (required)** `string` — 32-byte \`0x\`-prefixed hex string - **`portfolioId` (required)** `string` - **`recipientAccountId` (required)** `string` - **`liquidate`** `boolean`, default: `false` — Echoed verbatim from stage 1. When true, the authorization swaps \`assets\` to \`settlementAssetId\` and delivers it to the recipient. Defaults to false if omitted. - **`settlementAssetId`** `string` — Echoed verbatim from stage 1. CAIP-19 settlement asset on the same chain as \`recipientAccountId\` and every \`assets\[].assetId\`: configured USDC or USDT for an EVM withdrawal, or USDC for a Solana withdrawal. It does not enable cross-chain delivery or bridging. Omitted for plain transfers. **Example:** ```json { "portfolioId": "", "recipientAccountId": "", "assets": [ { "assetId": "", "amountRaw": "1500500000" } ], "nonce": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", "expiresAt": 1776384600, "liquidate": false, "settlementAssetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } ``` ### LiquidateAllSignatureRequest - **Type:**`object` * **`recipientAccountId` (required)** `string` — CAIP-10 recipient on the chain to liquidate — EVM (\`eip155:\:\\`) or Solana (\`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\\`). Every holding on that chain above the tenant swap threshold is swapped to the \`settlementAssetId\` settlement asset (USDC by default) and delivered here. Holdings on other chains are untouched — liquidate each chain separately. \`settlementAssetId\` must use this same chain; cross-chain delivery and bridging are not supported. * **`settlementAssetId`** `string` — CAIP-19 settlement asset on the same chain as \`recipientAccountId\`. For an EVM liquidation, use configured USDC or USDT on that EVM chain. For a Solana liquidation, use Solana USDC. Omit to default to USDC on the liquidation chain. This field does not select a different destination chain or enable bridging. **Example:** ```json { "recipientAccountId": "eip155:8453:0x4444444444444444444444444444444444444444", "settlementAssetId": "eip155:56/erc20:0x55d398326f99059fF775485246999027B3197955" } ``` ### ActivateChainsSignatureResponse - **Type:**`object` * **`data` (required)** `object` - **`message` (required)** `object` — The signable chain-activation message. Deterministic for a given (portfolio, chainIds) pair — repeating this call returns the same message. ECDSA portfolios get \`{ kind: "ecdsa", raw }\` (a session-key merkle root over the requested chains, signed via EIP-191 personal\_sign); ERC-1271 portfolios get \`{ kind: "typed-data", typedData }\` (EIP-712 payload signed with the owner's smart-contract wallet). * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "message": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" } } } ``` ### ActivateChainsSignatureData - **Type:**`object` * **`message` (required)** `object` — The signable chain-activation message. Deterministic for a given (portfolio, chainIds) pair — repeating this call returns the same message. ECDSA portfolios get \`{ kind: "ecdsa", raw }\` (a session-key merkle root over the requested chains, signed via EIP-191 personal\_sign); ERC-1271 portfolios get \`{ kind: "typed-data", typedData }\` (EIP-712 payload signed with the owner's smart-contract wallet). **Example:** ```json { "message": { "kind": "ecdsa", "raw": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" } } ``` ### ActivateChainsSignatureRequest - **Type:**`object` * **`chainIds` (required)** `array` — Numeric chain ids to activate on the portfolio. Must be a subset of the chains this deployment has RPCs configured for, must not contain duplicates, and must not include chains the portfolio is already active on. ERC-1271 portfolios sign one chain per signature, so they must pass exactly one chain id. **Items:** `integer` **Example:** ```json { "chainIds": [ 42161 ] } ``` ### ActivateChainsResponse - **Type:**`object` * **`data` (required)** `object` - **`portfolioId` (required)** `string` — Portfolio identifier - **`smartAccounts` (required)** `array` — Canonical SmartAccount objects, one per newly activated chain. Deterministic CREATE2 addresses — the same address as the portfolio's existing smart accounts, now live on the new chains. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ] } } ``` ### ActivateChainsData - **Type:**`object` * **`portfolioId` (required)** `string` — Portfolio identifier * **`smartAccounts` (required)** `array` — Canonical SmartAccount objects, one per newly activated chain. Deterministic CREATE2 addresses — the same address as the portfolio's existing smart accounts, now live on the new chains. **Items:** - **`accountId` (required)** `string` — CAIP-10 account identifier for the smart account (Kernel smart account). Always chain-bound — the same smart account address on a different chain is a different account. - **`depositAccountId`** `string` — SVM B2B only: CAIP-10 of the Swig sub-account the user sends funds to (the deposit address). On the SVM subaccount path this equals \`accountId\` — the canonical smart-account address IS the fundable sub-account. Omitted for EVM and SVM create-only accounts. - **`swigRoleId`** `integer` — SVM B2B only: the Swig role id that owns the sub-account (1 for the first vault of a tenant+user, higher for subsequent reused-Swig vaults). Omitted for EVM and SVM create-only accounts. **Example:** ```json { "portfolioId": "a1b2c3d4", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ] } ``` ### ActivateChainsRequest - **Type:**`object` * **`chainIds` (required)** `array` — Numeric chain ids to activate (no duplicates). Must exactly match the \`chainIds\` passed to \`POST /v2/portfolios/{portfolioId}/chains/signature\` — the signature was produced over that set. ERC-1271 portfolios activate one chain per request. **Items:** `integer` * **`signature` (required)** `string` — The portfolio owner's signature over the message returned by \`POST /v2/portfolios/{portfolioId}/chains/signature\`: an EIP-191 personal\_sign signature over \`message.raw\` for ECDSA portfolios, or the smart-contract wallet's ERC-1271 signature over \`message.typedData\` for ERC-1271 portfolios. **Example:** ```json { "chainIds": [ 42161 ], "signature": "0x9412d70d539f889ecec2d3152b68af758d689a4325a43b07811ee708814527c72256fc749d7fd3745a07f0aaa84813955050c461392d9b9ee1f80e106fac39e01b" } ``` ### GetOperationResponse - **Type:**`object` * **`data` (required)** `object` - **`createdAt` (required)** `string` — ISO 8601 creation timestamp - **`error` (required)** `string | null` — Free-form error message. Populated only when the operation reaches \`failed\` or \`cancelled\`. - **`finishedAt` (required)** `string | null` — ISO 8601 timestamp at which the operation reached a terminal state. Null while in-flight. - **`kind` (required)** `string`, possible values: `"withdraw", "rebalance", "bridge", "swap", "deposit", "transfer", "execution"` — Kind of async operation. Values are emitted by v2 portfolio writes, execution streams, and internal rebalance/swap/bridge flows. - **`operationId` (required)** `string` — Async operation identifier - **`portfolioId` (required)** `string` — Portfolio identifier - **`state` (required)** `string`, possible values: `"accepted", "running", "retrying", "awaiting_user", "completed", "failed", "cancelled"` — Current execution state. Terminal states: \`completed\`, \`failed\`, \`cancelled\`. - **`updatedAt` (required)** `string` — ISO 8601 last-update timestamp * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4", "portfolioId": "a1b2c3d4", "kind": "withdraw", "state": "running", "createdAt": "2026-04-17T12:00:00.000Z", "updatedAt": "2026-04-17T12:05:00.000Z", "finishedAt": "2026-04-17T12:05:00.000Z", "error": null } } ``` ### Operation - **Type:**`object` * **`createdAt` (required)** `string` — ISO 8601 creation timestamp * **`error` (required)** `string | null` — Free-form error message. Populated only when the operation reaches \`failed\` or \`cancelled\`. * **`finishedAt` (required)** `string | null` — ISO 8601 timestamp at which the operation reached a terminal state. Null while in-flight. * **`kind` (required)** `string`, possible values: `"withdraw", "rebalance", "bridge", "swap", "deposit", "transfer", "execution"` — Kind of async operation. Values are emitted by v2 portfolio writes, execution streams, and internal rebalance/swap/bridge flows. * **`operationId` (required)** `string` — Async operation identifier * **`portfolioId` (required)** `string` — Portfolio identifier * **`state` (required)** `string`, possible values: `"accepted", "running", "retrying", "awaiting_user", "completed", "failed", "cancelled"` — Current execution state. Terminal states: \`completed\`, \`failed\`, \`cancelled\`. * **`updatedAt` (required)** `string` — ISO 8601 last-update timestamp **Example:** ```json { "operationId": "op_01JWZEE2MF30KVRMRX53N88VA4", "portfolioId": "a1b2c3d4", "kind": "withdraw", "state": "running", "createdAt": "2026-04-17T12:00:00.000Z", "updatedAt": "2026-04-17T12:05:00.000Z", "finishedAt": "2026-04-17T12:05:00.000Z", "error": null } ``` ### PatchPortfolioResponse - **Type:**`object` * **`data` (required)** `object` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ### PatchPortfolioRequest - **Type:**`object` * **`portfolioName`** `string | null` — Integrator-provided display name for the portfolio. Trimmed server-side. Max 64 characters. Supports Unicode letters, digits, spaces, and - \_ . ' : ( ) & /. **Example:** ```json { "portfolioName": "Alice's Portfolio" } ``` ### GetPortfolioResponse - **Type:**`object` * **`data` (required)** `object` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "portfolioId": "a1b2c3d4", "portfolioName": "Alice's Portfolio", "ownerAccountId": "eip155:0:0xabcdef0000000000000000000000000000000001", "strategyId": "01JWZEE2MF30KVRMRX53N88VA4", "strategyName": "Conservative Yield", "strategyDescription": "Multi-chain balanced allocation strategy", "smartAccounts": [ { "accountId": "eip155:8453:0xe3a2d1f49aee887e42655b56371d4d76bbf58058", "depositAccountId": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9", "swigRoleId": 1 } ], "schedule": { "status": "active", "frequency": "daily", "intervalMs": 86400000, "nextDueAt": "2026-04-18T12:00:00.000Z", "lastRebalanceAt": "2026-04-17T12:00:00.000Z" }, "createdAt": "2026-04-17T12:00:00.000Z", "strategyVersion": 3, "updatedAt": "2026-04-17T12:05:00.000Z" } } ``` ### AssetAllocationBreakdownResponse - **Type:**`object` * **`data` (required)** `object` - **`breakdowns` (required)** `array` **Items:** - **`absoluteTotalWeight` (required)** `string` - **`aggregationMode` (required)** `string`, possible values: `"apportioned", "overlap", "primary", "single"` - **`buckets` (required)** `array` **Items:** - **`absoluteWeight` (required)** `string` - **`holdingCount` (required)** `integer` - **`holdings` (required)** `array` **Items:** - **`absoluteWeight` (required)** `string` - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`contributionWeight` (required)** `string` - **`inputIndex` (required)** `integer` - **`name` (required)** `string | null` - **`resolutionPath` (required)** `string`, possible values: `"input_canonical", "product_route", "token_subject_link", "unresolved"` - **`symbol` (required)** `string | null` - **`key` (required)** `string` - **`label` (required)** `string` - **`weight` (required)** `string` - **`dimension` (required)** `string`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory"` - **`totalMayExceedOne` (required)** `boolean` - **`totalWeight` (required)** `string` - **`diagnostics` (required)** `object` - **`lowConfidence` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`confidence` (required)** `integer` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`sectorClassification` (required)** `object` - **`asOfDate` (required)** `string | null` - **`confidence` (required)** `integer` - **`displaySector` (required)** `string` - **`resolvedAt` (required)** `string` - **`resolverVersion` (required)** `string` - **`sicCode` (required)** `string | null` - **`sicDescription` (required)** `string | null` - **`source` (required)** `string` - **`sourceIndustry` (required)** `string | null` - **`sourceIndustryGroup` (required)** `string | null` - **`sourceKeyType` (required)** `string | null` - **`sourceKeyValue` (required)** `string | null` - **`sourceRank` (required)** `integer` - **`sourceSector` (required)** `string | null` - **`sourceSubIndustry` (required)** `string | null` - **`taxonomy` (required)** `string`, possible values: `"internal_display_sector_v1"` - **`symbol` (required)** `string | null` - **`unclassified` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`unresolved` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`unsupported` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`dimension` (required)** `string | null`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory", null` - **`inputIndex` (required)** `integer` - **`normalizedWeight` (required)** `string` - **`reason` (required)** `string` - **`symbol` (required)** `string | null` - **`holdings` (required)** `array` **Items:** - **`assetCanonicalId` (required)** `string | null` - **`caipAssetId` (required)** `string | null` - **`inputIndex` (required)** `integer` - **`name` (required)** `string | null` - **`normalizedWeight` (required)** `string` - **`sourceValue` (required)** `string` - **`symbol` (required)** `string | null` - **`normalization` (required)** `object` - **`inputMode` (required)** `string`, possible values: `"equal", "marketValueUsd", "weights"` - **`normalizedTotal` (required)** `string` - **`sourceTotal` (required)** `string` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "breakdowns": [ { "absoluteTotalWeight": "", "aggregationMode": "apportioned", "buckets": [ { "absoluteWeight": "", "holdingCount": 0, "holdings": [ { "absoluteWeight": "", "assetCanonicalId": null, "caipAssetId": null, "contributionWeight": "", "inputIndex": 0, "name": null, "resolutionPath": "input_canonical", "symbol": null } ], "key": "", "label": "", "weight": "" } ], "dimension": "sector", "totalMayExceedOne": true, "totalWeight": "" } ], "diagnostics": { "lowConfidence": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null, "confidence": 0, "sectorClassification": { "asOfDate": null, "confidence": 0, "displaySector": "", "resolverVersion": "", "resolvedAt": "", "sicCode": null, "sicDescription": null, "source": "", "sourceIndustry": null, "sourceIndustryGroup": null, "sourceKeyType": null, "sourceKeyValue": null, "sourceRank": 1, "sourceSector": null, "sourceSubIndustry": null, "taxonomy": "internal_display_sector_v1" } } ], "unclassified": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null } ], "unresolved": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null } ], "unsupported": [ { "assetCanonicalId": null, "caipAssetId": null, "dimension": "sector", "inputIndex": 0, "normalizedWeight": "", "reason": "", "symbol": null } ] }, "holdings": [ { "assetCanonicalId": null, "caipAssetId": null, "inputIndex": 0, "name": null, "normalizedWeight": "", "sourceValue": "", "symbol": null } ], "normalization": { "inputMode": "equal", "normalizedTotal": "", "sourceTotal": "" } } } ``` ### AssetAllocationBreakdownRequest - **Type:**`object` * **`holdings` (required)** `array` **Items:** - **`assetCanonicalId`** `string | null`, format: `uuid` - **`caipAssetId`** `string | null` - **`marketValueUsd`** `string | null` - **`name`** `string | null` - **`symbol`** `string | null` - **`weight`** `string | null` * **`dimensions`** `array` **Items:** `string`, possible values: `"sector", "industryGroup", "industry", "subIndustry", "gliderSector", "gliderTheme", "cryptoCategory"` * **`includeHoldings`** `boolean` * **`multiCategoryMode`** `string`, possible values: `"primary", "apportioned", "overlap"` **Example:** ```json { "dimensions": [ "sector" ], "holdings": [ { "assetCanonicalId": null, "caipAssetId": null, "marketValueUsd": null, "name": null, "symbol": null, "weight": null } ], "includeHoldings": true, "multiCategoryMode": "primary" } ``` ### CampaignPortfoliosResponse - **Type:**`object` * **`data` (required)** `object` - **`campaignId` (required)** `string` - **`portfolios` (required)** `array` **Items:** - **`assets` (required)** `array` **Items:** - **`assetId` (required)** `string` - **`balance` (required)** `string` — Human-readable token balance - **`balanceRaw` (required)** `string` — Raw integer token balance (no decimals applied) - **`decimals` (required)** `integer` - **`symbol` (required)** `string` - **`valueUsd` (required)** `string` — USD value, formatted to 6 decimal places - **`createdAt` (required)** `string` — ISO 8601 timestamp - **`portfolioId` (required)** `string` — Unique portfolio identifier - **`totalValueUsd` (required)** `string` — Total value locked in USD, formatted to 6 decimal places - **`vaults` (required)** `array` **Items:** - **`vaultId` (required)** `string` - **`strategyId` (required)** `string` * **`nextCursor` (required)** `string | null` * **`success` (required)** `boolean`, possible values: `true` **Example:** ```json { "success": true, "data": { "campaignId": "", "strategyId": "", "portfolios": [ { "portfolioId": "", "totalValueUsd": "1500.500000", "vaults": [ { "vaultId": "eip155:1:0xe3a2d1f49aee887e42655b56371d4d76bbf58058" } ], "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "valueUsd": "500.013232", "symbol": "USDC", "balance": "500.013232", "balanceRaw": "500013232", "decimals": 6 } ], "createdAt": "2025-01-01T10:00:00.000Z" } ] }, "nextCursor": null } ``` ### CampaignPortfolio - **Type:**`object` * **`assets` (required)** `array` **Items:** - **`assetId` (required)** `string` - **`balance` (required)** `string` — Human-readable token balance - **`balanceRaw` (required)** `string` — Raw integer token balance (no decimals applied) - **`decimals` (required)** `integer` - **`symbol` (required)** `string` - **`valueUsd` (required)** `string` — USD value, formatted to 6 decimal places * **`createdAt` (required)** `string` — ISO 8601 timestamp * **`portfolioId` (required)** `string` — Unique portfolio identifier * **`totalValueUsd` (required)** `string` — Total value locked in USD, formatted to 6 decimal places * **`vaults` (required)** `array` **Items:** - **`vaultId` (required)** `string` **Example:** ```json { "portfolioId": "", "totalValueUsd": "1500.500000", "vaults": [ { "vaultId": "eip155:1:0xe3a2d1f49aee887e42655b56371d4d76bbf58058" } ], "assets": [ { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "valueUsd": "500.013232", "symbol": "USDC", "balance": "500.013232", "balanceRaw": "500013232", "decimals": 6 } ], "createdAt": "2025-01-01T10:00:00.000Z" } ``` ### CampaignPortfolioVault - **Type:**`object` * **`vaultId` (required)** `string` **Example:** ```json { "vaultId": "eip155:1:0xe3a2d1f49aee887e42655b56371d4d76bbf58058" } ``` ### CampaignPortfolioAsset - **Type:**`object` * **`assetId` (required)** `string` * **`balance` (required)** `string` — Human-readable token balance * **`balanceRaw` (required)** `string` — Raw integer token balance (no decimals applied) * **`decimals` (required)** `integer` * **`symbol` (required)** `string` * **`valueUsd` (required)** `string` — USD value, formatted to 6 decimal places **Example:** ```json { "assetId": "eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "valueUsd": "500.013232", "symbol": "USDC", "balance": "500.013232", "balanceRaw": "500013232", "decimals": 6 } ```