Last active
December 4, 2025 00:56
-
-
Save Olshansk/6d59228aaf37347c118ea84fb0579cf0 to your computer and use it in GitHub Desktop.
Grove API OpenAPI Spec
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "openapi": "3.1.0", | |
| "info": { | |
| "title": "Grove API", | |
| "description": "Grove API: Custodial tipping service for frictionless online tipping.", | |
| "version": "1.0.0" | |
| }, | |
| "paths": { | |
| "/health": { | |
| "get": { | |
| "summary": "Health", | |
| "description": "Health check endpoint", | |
| "operationId": "health_health_get", | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": {} | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/fund": { | |
| "post": { | |
| "tags": [ | |
| "funding" | |
| ], | |
| "summary": "Create or fund a Grove tipping account using x402 payments", | |
| "description": "Fund a Grove tipping account using x402 payments.\n\nBehavior:\n\n1. New account flow (no `Authorization`):\n 1. Call without `X-PAYMENT` to receive HTTP 402 with x402 payment requirements.\n 2. Sign the payment using the provided requirements.\n 3. Call again with `X-PAYMENT` set to the signed payload.\n 4. On success, a custodial wallet and Grove account are created and funded, and an `api_key` JWT is returned.\n\n2. Existing account flow (with `Authorization`):\n 1. Call with a valid `Authorization: Bearer <api_key>` header and no `X-PAYMENT` to receive HTTP 402.\n 2. Sign the payment and call again with both `Authorization` and `X-PAYMENT`.\n 3. On success, the existing account balance is increased.\n\nIn both flows, the endpoint:\n\n- Verifies the x402 payment locally.\n- Settles the payment using the configured facilitator.\n- Waits for the provider-reported balance to reflect the funded amount.\n- Returns the funded amount, new balance, and settlement transaction hash.\n\nThe `FundResponse` payload:\n\n- For new accounts: includes `funded_amount`, `new_balance`, `tx_hash`, `account_id`, and `api_key`.\n- For existing accounts: includes `funded_amount`, `new_balance`, and `tx_hash`.\n\nMulti-network support:\n- Specify `network` and `token` query params to fund with specific asset\n- Defaults to DEFAULT_NETWORK and DEFAULT_TOKEN if not specified\n- Account.network is set on first funding (immutable - represents VM type)\n- Multi-network balances tracked in AccountBalance table", | |
| "operationId": "fund_account_v1_fund_post", | |
| "parameters": [ | |
| { | |
| "name": "amount", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "string", | |
| "description": "\n Amount to credit to the tipping account.\n\n Unit: human-readable amount (not atomic units), for example `\"0.10\"`, `\"1\"`, `\"5.25\"`.\n\n Purpose: this balance is used by an agent or human to tip content creators (agents or humans) on the internet.\n\n Flow:\n - Without `Authorization`: creates a new Grove account, funds it, and returns an `api_key` JWT.\n - With `Authorization`: funds the existing Grove account associated with that JWT.\n\n Constraints:\n - Must be a positive number.\n - Precision must not exceed the configured decimals for the token.\n ", | |
| "default": "1", | |
| "title": "Amount" | |
| }, | |
| "description": "\n Amount to credit to the tipping account.\n\n Unit: human-readable amount (not atomic units), for example `\"0.10\"`, `\"1\"`, `\"5.25\"`.\n\n Purpose: this balance is used by an agent or human to tip content creators (agents or humans) on the internet.\n\n Flow:\n - Without `Authorization`: creates a new Grove account, funds it, and returns an `api_key` JWT.\n - With `Authorization`: funds the existing Grove account associated with that JWT.\n\n Constraints:\n - Must be a positive number.\n - Precision must not exceed the configured decimals for the token.\n " | |
| }, | |
| { | |
| "name": "network", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "\n Network identifier (e.g., \"base\", \"base-sepolia\").\n\n Supported networks: ethereum-mainnet, base-sepolia, base, solana-devnet, solana-testnet, solana-mainnet.\n\n Defaults to: base-sepolia\n\n Note: The account's primary network (Account.network) is set on first funding and\n represents the Virtual Machine (EVM, SVM, etc.). Multi-network balances are tracked\n separately in the AccountBalance table.\n ", | |
| "title": "Network" | |
| }, | |
| "description": "\n Network identifier (e.g., \"base\", \"base-sepolia\").\n\n Supported networks: ethereum-mainnet, base-sepolia, base, solana-devnet, solana-testnet, solana-mainnet.\n\n Defaults to: base-sepolia\n\n Note: The account's primary network (Account.network) is set on first funding and\n represents the Virtual Machine (EVM, SVM, etc.). Multi-network balances are tracked\n separately in the AccountBalance table.\n " | |
| }, | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "\n Token symbol (e.g., \"USDC\", \"ETH\").\n\n Defaults to: USDC\n\n Supported tokens vary by network. Check the network's token configuration for available options.\n ", | |
| "title": "Token" | |
| }, | |
| "description": "\n Token symbol (e.g., \"USDC\", \"ETH\").\n\n Defaults to: USDC\n\n Supported tokens vary by network. Check the network's token configuration for available options.\n " | |
| }, | |
| { | |
| "name": "authorization", | |
| "in": "header", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "\n Optional Bearer JWT issued by Grove that identifies an existing tipping account.\n\n Format: `Authorization: Bearer <api_key>`.\n\n When absent:\n - A new server wallet and Grove account are created after successful payment.\n - A new `api_key` is returned and should be used as the Bearer token in future calls.\n\n When present:\n - The call is treated as a top-up for the existing account.\n - The response includes the new balance but does not issue a new `api_key`.\n ", | |
| "title": "Authorization" | |
| }, | |
| "description": "\n Optional Bearer JWT issued by Grove that identifies an existing tipping account.\n\n Format: `Authorization: Bearer <api_key>`.\n\n When absent:\n - A new server wallet and Grove account are created after successful payment.\n - A new `api_key` is returned and should be used as the Bearer token in future calls.\n\n When present:\n - The call is treated as a top-up for the existing account.\n - The response includes the new balance but does not issue a new `api_key`.\n " | |
| }, | |
| { | |
| "name": "X-PAYMENT", | |
| "in": "header", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "\n Base64-encoded x402 payment payload returned by the x402 signer.\n\n This header participates in a two-step x402 funding flow:\n\n 1. First request:\n - Call `/v1/fund` without `X-PAYMENT` (and optionally with `Authorization`).\n - The API responds with HTTP 402 and an `accepts` array describing the required payment.\n\n 2. Second request:\n - Sign the x402 payment off-platform using the details from the 402 response.\n - Call `/v1/fund` again with the `X-PAYMENT` header set to the signed payload.\n - On success, the payment is verified and settled, and the account is created or funded.\n\n If this header is missing on the second step, the API always responds with HTTP 402 and updated\n payment requirements.\n ", | |
| "title": "X-Payment" | |
| }, | |
| "description": "\n Base64-encoded x402 payment payload returned by the x402 signer.\n\n This header participates in a two-step x402 funding flow:\n\n 1. First request:\n - Call `/v1/fund` without `X-PAYMENT` (and optionally with `Authorization`).\n - The API responds with HTTP 402 and an `accepts` array describing the required payment.\n\n 2. Second request:\n - Sign the x402 payment off-platform using the details from the 402 response.\n - Call `/v1/fund` again with the `X-PAYMENT` header set to the signed payload.\n - On success, the payment is verified and settled, and the account is created or funded.\n\n If this header is missing on the second step, the API always responds with HTTP 402 and updated\n payment requirements.\n " | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/FundResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/tip/{destination}/{amount}": { | |
| "post": { | |
| "tags": [ | |
| "tipping" | |
| ], | |
| "summary": "Send a tip via URL path (REST-style)", | |
| "description": "Send a tip using URL path parameters.\n\nThis REST-style endpoint puts destination and amount in the URL path,\nwith optional network/token as query parameters.\n\n**Example requests:**\n```\nPOST /v1/tip/olshansky.info/0.01?network=base&token=USDC\nPOST /v1/tip/x.com/olshansky/$1\nPOST /v1/tip/0x9ab39B84aC4DE6D705C5f051c07db8fE72890953/100USDC\n```", | |
| "operationId": "tip_destination_path_v1_tip__destination___amount__post", | |
| "parameters": [ | |
| { | |
| "name": "destination", | |
| "in": "path", | |
| "required": true, | |
| "schema": { | |
| "type": "string", | |
| "description": "Who to tip. Accepts multiple formats:\n\n- **EVM address**: `0x9ab39B84aC4DE6D705C5f051c07db8fE72890953`\n- **Solana address**: `9kucRUCUiYwJLDBBi5GXb4KeqgiRZ6uJeMdLwAuV6pUC`\n- **ENS name**: `vitalik.eth` (resolved via Ethereum mainnet)\n- **Domain**: `olshansky.info` (looks up address from llms.txt)\n- **Twitter/X**: `x.com/olshansky` (looks up address from bio)\n\nNote: Uses `:path` converter to support slashes in Twitter URLs.", | |
| "examples": [ | |
| "0x9ab39B84aC4DE6D705C5f051c07db8fE72890953", | |
| "olshansky.info", | |
| "x.com/olshansky" | |
| ], | |
| "title": "Destination" | |
| }, | |
| "description": "Who to tip. Accepts multiple formats:\n\n- **EVM address**: `0x9ab39B84aC4DE6D705C5f051c07db8fE72890953`\n- **Solana address**: `9kucRUCUiYwJLDBBi5GXb4KeqgiRZ6uJeMdLwAuV6pUC`\n- **ENS name**: `vitalik.eth` (resolved via Ethereum mainnet)\n- **Domain**: `olshansky.info` (looks up address from llms.txt)\n- **Twitter/X**: `x.com/olshansky` (looks up address from bio)\n\nNote: Uses `:path` converter to support slashes in Twitter URLs." | |
| }, | |
| { | |
| "name": "amount", | |
| "in": "path", | |
| "required": true, | |
| "schema": { | |
| "type": "string", | |
| "description": "Amount to tip. Supports multiple formats:\n\n- **Plain number**: `0.01` (uses token from query or DEFAULT_TOKEN)\n- **With currency suffix**: `100USDC`, `0.5ETH`\n- **Dollar prefix**: `$1` (interpreted as 1 USDC)", | |
| "examples": [ | |
| "0.01", | |
| "100USDC", | |
| "$1" | |
| ], | |
| "title": "Amount" | |
| }, | |
| "description": "Amount to tip. Supports multiple formats:\n\n- **Plain number**: `0.01` (uses token from query or DEFAULT_TOKEN)\n- **With currency suffix**: `100USDC`, `0.5ETH`\n- **Dollar prefix**: `$1` (interpreted as 1 USDC)" | |
| }, | |
| { | |
| "name": "network", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "Target blockchain network.\n\nExamples: `base`, `base-sepolia`, `solana-devnet`.\n\nDefaults to DEFAULT_NETWORK (base-sepolia) if not specified.", | |
| "examples": [ | |
| "base", | |
| "base-sepolia" | |
| ], | |
| "title": "Network" | |
| }, | |
| "description": "Target blockchain network.\n\nExamples: `base`, `base-sepolia`, `solana-devnet`.\n\nDefaults to DEFAULT_NETWORK (base-sepolia) if not specified." | |
| }, | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "Token symbol to send.\n\nExamples: `USDC`, `ETH`.\n\nDefaults to DEFAULT_TOKEN (USDC) if not specified.\n\n**Conflict detection**: If the amount path includes a token (e.g., `100USDC`) and this query param specifies a *different* token (e.g., `?token=ETH`), the request fails with HTTP 400.", | |
| "examples": [ | |
| "USDC", | |
| "ETH" | |
| ], | |
| "title": "Token" | |
| }, | |
| "description": "Token symbol to send.\n\nExamples: `USDC`, `ETH`.\n\nDefaults to DEFAULT_TOKEN (USDC) if not specified.\n\n**Conflict detection**: If the amount path includes a token (e.g., `100USDC`) and this query param specifies a *different* token (e.g., `?token=ETH`), the request fails with HTTP 400." | |
| }, | |
| { | |
| "name": "authorization", | |
| "in": "header", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "Bearer JWT that identifies the sending account.\n\n- **Required** for all tipping calls\n- Format: `Bearer <jwt_token>`\n- Obtain JWT from `/v1/fund` after funding your account", | |
| "title": "Authorization" | |
| }, | |
| "description": "Bearer JWT that identifies the sending account.\n\n- **Required** for all tipping calls\n- Format: `Bearer <jwt_token>`\n- Obtain JWT from `/v1/fund` after funding your account" | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/TipResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/tip": { | |
| "post": { | |
| "tags": [ | |
| "tipping" | |
| ], | |
| "summary": "Send a tip via JSON body", | |
| "description": "Send a tip using a JSON request body.\n\nThis endpoint accepts all parameters in the request body, which is useful\nfor programmatic access or when destinations contain special characters.\n\n**Example request:**\n```json\n{\n \"destination\": \"olshansky.info\",\n \"amount\": \"0.01\",\n \"network\": \"base\",\n \"token\": \"USDC\"\n}\n```", | |
| "operationId": "tip_destination_body_v1_tip_post", | |
| "parameters": [ | |
| { | |
| "name": "authorization", | |
| "in": "header", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "Bearer JWT that identifies the sending account.\n\n- **Required** for all tipping calls\n- Format: `Bearer <jwt_token>`\n- Obtain JWT from `/v1/fund` after funding your account", | |
| "title": "Authorization" | |
| }, | |
| "description": "Bearer JWT that identifies the sending account.\n\n- **Required** for all tipping calls\n- Format: `Bearer <jwt_token>`\n- Obtain JWT from `/v1/fund` after funding your account" | |
| } | |
| ], | |
| "requestBody": { | |
| "required": true, | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/TipRequest" | |
| } | |
| } | |
| } | |
| }, | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/TipResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/auth/recover": { | |
| "post": { | |
| "tags": [ | |
| "auth" | |
| ], | |
| "summary": "Recover JWT for an account using the funding wallet signature", | |
| "description": "Recover an account's existing JWT by proving control of the funding wallet.\n\nSecurity notes:\n- TODO: Rotate JWT instead of re-issuing the stored token so lost keys are invalidated.\n- TODO: Replace static messages with a nonce-based challenge to prevent replay attacks.", | |
| "operationId": "recover_account_v1_auth_recover_post", | |
| "requestBody": { | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/RecoverRequest" | |
| } | |
| } | |
| }, | |
| "required": true | |
| }, | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/RecoverResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/account": { | |
| "get": { | |
| "tags": [ | |
| "account" | |
| ], | |
| "summary": "Retrieve account metadata and cached balances", | |
| "description": "Get a snapshot of the authenticated account, including:\n\n- `account_id`: Grove account ID bound to the JWT.\n- `client_address`: The non-custodial wallet that created/funded the account (x402 payer).\n- `onchain_address`: The Grove-managed custodial wallet address.\n- `metadata`: Arbitrary key/value metadata (currently unvalidated).\n- `balances`: Cached balances across networks/tokens (no provider refresh).\n\nAuthentication: `Authorization: Bearer <CLIENT_JWT>`\n\nNotes:\n- Balances are returned from the database cache only. TODO: add an opt-in refresh flag to hit the provider.\n- Metadata structure is TBD; today it is returned as-is.", | |
| "operationId": "get_account_v1_account_get", | |
| "parameters": [ | |
| { | |
| "name": "authorization", | |
| "in": "header", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "Bearer JWT issued by Grove that identifies the account.", | |
| "title": "Authorization" | |
| }, | |
| "description": "Bearer JWT issued by Grove that identifies the account." | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/AccountGetResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "post": { | |
| "tags": [ | |
| "account" | |
| ], | |
| "summary": "Update account metadata", | |
| "description": "Merge user-provided metadata into the account and return the updated snapshot.\n\nAuthentication: `Authorization: Bearer <CLIENT_JWT>`\n\nRequest body:\n- `metadata` (object, optional): Arbitrary key/value pairs to merge. Existing keys are overwritten by new ones.\n\nNotes / TODOs:\n- Define allowed/reserved metadata keys and size limits before widening usage.\n- Add email account support and determine how to integrate with other OAuth flows.", | |
| "operationId": "update_account_v1_account_post", | |
| "parameters": [ | |
| { | |
| "name": "authorization", | |
| "in": "header", | |
| "required": false, | |
| "schema": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "description": "Bearer JWT issued by Grove that identifies the account.", | |
| "title": "Authorization" | |
| }, | |
| "description": "Bearer JWT issued by Grove that identifies the account." | |
| } | |
| ], | |
| "requestBody": { | |
| "required": true, | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/AccountUpdateRequest" | |
| } | |
| } | |
| } | |
| }, | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/AccountGetResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/leaderboard/tippers": { | |
| "get": { | |
| "tags": [ | |
| "leaderboard" | |
| ], | |
| "summary": "Get top tippers leaderboard", | |
| "description": "Get the top tippers leaderboard (public, no auth).\n\n- Ranks by total amount tipped (USD) in the requested window.\n- Always returns the tipper\u2019s Grove custodial address.\n- `window` examples:\n - `24h`: tips in the last 24 hours\n - `7d`: tips in the last 7 days\n - `30d`: tips in the last 30 days\n - `all`: all-time rollup (fast path, no aggregation)", | |
| "operationId": "get_tippers_leaderboard_v1_leaderboard_tippers_get", | |
| "parameters": [ | |
| { | |
| "name": "window", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "enum": [ | |
| "24h", | |
| "7d", | |
| "30d", | |
| "all" | |
| ], | |
| "type": "string", | |
| "description": "Time window: '24h', '7d', '30d', or 'all' (all time).", | |
| "default": "all", | |
| "title": "Window" | |
| }, | |
| "description": "Time window: '24h', '7d', '30d', or 'all' (all time)." | |
| }, | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "string", | |
| "description": "Token symbol to filter by.", | |
| "default": "USDC", | |
| "title": "Token" | |
| }, | |
| "description": "Token symbol to filter by." | |
| }, | |
| { | |
| "name": "limit", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "integer", | |
| "maximum": 500, | |
| "minimum": 1, | |
| "description": "Maximum number of entries to return.", | |
| "default": 100, | |
| "title": "Limit" | |
| }, | |
| "description": "Maximum number of entries to return." | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/LeaderboardResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/leaderboard/tippees": { | |
| "get": { | |
| "tags": [ | |
| "leaderboard" | |
| ], | |
| "summary": "Get top tippees (tip recipients) leaderboard", | |
| "description": "Get the top tippees (tip recipients) leaderboard (public, no auth).\n\n- Ranks by total amount received (USD) in the requested window.\n- Includes recipients without a Grove account (address only).\n- `window` examples:\n - `24h`: tips received in the last 24 hours\n - `7d`: tips received in the last 7 days\n - `30d`: tips received in the last 30 days\n - `all`: all-time rollup (fast path, no aggregation)", | |
| "operationId": "get_tippees_leaderboard_v1_leaderboard_tippees_get", | |
| "parameters": [ | |
| { | |
| "name": "window", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "enum": [ | |
| "24h", | |
| "7d", | |
| "30d", | |
| "all" | |
| ], | |
| "type": "string", | |
| "description": "Time window: '24h', '7d', '30d', or 'all' (all time).", | |
| "default": "all", | |
| "title": "Window" | |
| }, | |
| "description": "Time window: '24h', '7d', '30d', or 'all' (all time)." | |
| }, | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "string", | |
| "description": "Token symbol to filter by.", | |
| "default": "USDC", | |
| "title": "Token" | |
| }, | |
| "description": "Token symbol to filter by." | |
| }, | |
| { | |
| "name": "limit", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "integer", | |
| "maximum": 500, | |
| "minimum": 1, | |
| "description": "Maximum number of entries to return.", | |
| "default": 100, | |
| "title": "Limit" | |
| }, | |
| "description": "Maximum number of entries to return." | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/LeaderboardResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/leaderboard/funders": { | |
| "get": { | |
| "tags": [ | |
| "leaderboard" | |
| ], | |
| "summary": "Get top funders leaderboard", | |
| "description": "Get the top funders leaderboard (public, no auth).\n\n- Ranks accounts by total funds deposited into Grove custodial wallets.\n- Includes first/last funded timestamps for context.\n- `window` examples:\n - `24h`: funding events in the last 24 hours\n - `7d`: funding events in the last 7 days\n - `30d`: funding events in the last 30 days\n - `all`: all-time rollup (fast path, no aggregation)", | |
| "operationId": "get_funders_leaderboard_endpoint_v1_leaderboard_funders_get", | |
| "parameters": [ | |
| { | |
| "name": "window", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "enum": [ | |
| "24h", | |
| "7d", | |
| "30d", | |
| "all" | |
| ], | |
| "type": "string", | |
| "description": "Time window: '24h', '7d', '30d', or 'all' (all time).", | |
| "default": "all", | |
| "title": "Window" | |
| }, | |
| "description": "Time window: '24h', '7d', '30d', or 'all' (all time)." | |
| }, | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "string", | |
| "description": "Token symbol to filter by.", | |
| "default": "USDC", | |
| "title": "Token" | |
| }, | |
| "description": "Token symbol to filter by." | |
| }, | |
| { | |
| "name": "limit", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "integer", | |
| "maximum": 500, | |
| "minimum": 1, | |
| "description": "Maximum number of entries to return.", | |
| "default": 100, | |
| "title": "Limit" | |
| }, | |
| "description": "Maximum number of entries to return." | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/FundersLeaderboardResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/leaderboard/funds/total": { | |
| "get": { | |
| "tags": [ | |
| "leaderboard" | |
| ], | |
| "summary": "Get total funds across all accounts", | |
| "description": "Get the aggregate total of all funds across all Grove accounts (public, no auth).\n\n- Represents the total \u201ctipping jar\u201d balance recorded in `fund_events`.\n- Useful for public dashboards or transparency pages.\n- Filterable by token symbol (default USDC).", | |
| "operationId": "get_funds_total_endpoint_v1_leaderboard_funds_total_get", | |
| "parameters": [ | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "string", | |
| "description": "Token symbol to filter by.", | |
| "default": "USDC", | |
| "title": "Token" | |
| }, | |
| "description": "Token symbol to filter by." | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/FundsTotalResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/leaderboard/tippers/recent": { | |
| "get": { | |
| "tags": [ | |
| "leaderboard" | |
| ], | |
| "summary": "Get most recent tips (tipper view)", | |
| "description": "Get the N most recent confirmed tips, showing tipper addresses (public, no auth).\n\n- Returns individual tip events ordered by confirmation time (most recent first).\n- Each entry shows the tipper's wallet address and tip details.\n- Useful for activity feeds or recent activity displays.", | |
| "operationId": "get_recent_tippers_v1_leaderboard_tippers_recent_get", | |
| "parameters": [ | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "string", | |
| "description": "Token symbol to filter by.", | |
| "default": "USDC", | |
| "title": "Token" | |
| }, | |
| "description": "Token symbol to filter by." | |
| }, | |
| { | |
| "name": "limit", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "integer", | |
| "maximum": 500, | |
| "minimum": 1, | |
| "description": "Number of recent tips to return.", | |
| "default": 100, | |
| "title": "Limit" | |
| }, | |
| "description": "Number of recent tips to return." | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/RecentTipsResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "/v1/leaderboard/tippees/recent": { | |
| "get": { | |
| "tags": [ | |
| "leaderboard" | |
| ], | |
| "summary": "Get most recent tips (tippee view)", | |
| "description": "Get the N most recent confirmed tips, showing tippee addresses (public, no auth).\n\n- Returns individual tip events ordered by confirmation time (most recent first).\n- Each entry shows the recipient's wallet address and tip details.\n- Includes recipients without a Grove account (external wallets).", | |
| "operationId": "get_recent_tippees_v1_leaderboard_tippees_recent_get", | |
| "parameters": [ | |
| { | |
| "name": "token", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "string", | |
| "description": "Token symbol to filter by.", | |
| "default": "USDC", | |
| "title": "Token" | |
| }, | |
| "description": "Token symbol to filter by." | |
| }, | |
| { | |
| "name": "limit", | |
| "in": "query", | |
| "required": false, | |
| "schema": { | |
| "type": "integer", | |
| "maximum": 500, | |
| "minimum": 1, | |
| "description": "Number of recent tips to return.", | |
| "default": 100, | |
| "title": "Limit" | |
| }, | |
| "description": "Number of recent tips to return." | |
| } | |
| ], | |
| "responses": { | |
| "200": { | |
| "description": "Successful Response", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/RecentTipsResponse" | |
| } | |
| } | |
| } | |
| }, | |
| "422": { | |
| "description": "Validation Error", | |
| "content": { | |
| "application/json": { | |
| "schema": { | |
| "$ref": "#/components/schemas/HTTPValidationError" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| "components": { | |
| "schemas": { | |
| "AccountBalance": { | |
| "properties": { | |
| "network": { | |
| "type": "string", | |
| "title": "Network" | |
| }, | |
| "token_symbol": { | |
| "type": "string", | |
| "title": "Token Symbol" | |
| }, | |
| "balance": { | |
| "type": "string", | |
| "title": "Balance" | |
| }, | |
| "contract_address": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Contract Address" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "network", | |
| "token_symbol", | |
| "balance" | |
| ], | |
| "title": "AccountBalance", | |
| "description": "Balance representation for an account across networks/tokens." | |
| }, | |
| "AccountGetResponse": { | |
| "properties": { | |
| "account_id": { | |
| "type": "string", | |
| "title": "Account Id" | |
| }, | |
| "client_address": { | |
| "type": "string", | |
| "title": "Client Address" | |
| }, | |
| "onchain_address": { | |
| "type": "string", | |
| "title": "Onchain Address" | |
| }, | |
| "metadata": { | |
| "anyOf": [ | |
| { | |
| "additionalProperties": true, | |
| "type": "object" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Metadata" | |
| }, | |
| "balances": { | |
| "items": { | |
| "$ref": "#/components/schemas/AccountBalance" | |
| }, | |
| "type": "array", | |
| "title": "Balances" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "account_id", | |
| "client_address", | |
| "onchain_address", | |
| "balances" | |
| ], | |
| "title": "AccountGetResponse", | |
| "description": "Response model for account metadata and balances." | |
| }, | |
| "AccountUpdateRequest": { | |
| "properties": { | |
| "metadata": { | |
| "anyOf": [ | |
| { | |
| "additionalProperties": true, | |
| "type": "object" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Metadata" | |
| } | |
| }, | |
| "type": "object", | |
| "title": "AccountUpdateRequest", | |
| "description": "Request model for updating account metadata." | |
| }, | |
| "FundResponse": { | |
| "properties": { | |
| "funded_amount": { | |
| "type": "string", | |
| "title": "Funded Amount" | |
| }, | |
| "new_balance": { | |
| "type": "string", | |
| "title": "New Balance" | |
| }, | |
| "tx_hash": { | |
| "type": "string", | |
| "title": "Tx Hash" | |
| }, | |
| "account_id": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Account Id" | |
| }, | |
| "api_key": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Api Key" | |
| }, | |
| "address": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Address" | |
| }, | |
| "client_address": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Client Address" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "funded_amount", | |
| "new_balance", | |
| "tx_hash" | |
| ], | |
| "title": "FundResponse", | |
| "description": "Response model for successful funding.\n\nWhen creating a new account (no JWT provided):\n- account_id, api_key, address, and client_address are populated\n- Use api_key as Bearer token for future requests\n\nWhen funding existing account (JWT provided):\n- account_id and api_key are None\n- address and client_address are populated" | |
| }, | |
| "FunderEntry": { | |
| "properties": { | |
| "rank": { | |
| "type": "integer", | |
| "title": "Rank" | |
| }, | |
| "account_id": { | |
| "type": "string", | |
| "title": "Account Id" | |
| }, | |
| "address": { | |
| "type": "string", | |
| "title": "Address" | |
| }, | |
| "total_amount_usd": { | |
| "type": "string", | |
| "title": "Total Amount Usd" | |
| }, | |
| "total_amount_raw": { | |
| "type": "string", | |
| "title": "Total Amount Raw" | |
| }, | |
| "fund_count": { | |
| "type": "integer", | |
| "title": "Fund Count" | |
| }, | |
| "unique_counterparty_count": { | |
| "type": "integer", | |
| "title": "Unique Counterparty Count" | |
| }, | |
| "first_funded_at": { | |
| "type": "string", | |
| "title": "First Funded At" | |
| }, | |
| "last_funded_at": { | |
| "type": "string", | |
| "title": "Last Funded At" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "rank", | |
| "account_id", | |
| "address", | |
| "total_amount_usd", | |
| "total_amount_raw", | |
| "fund_count", | |
| "unique_counterparty_count", | |
| "first_funded_at", | |
| "last_funded_at" | |
| ], | |
| "title": "FunderEntry", | |
| "description": "Entry in the funders leaderboard." | |
| }, | |
| "FundersLeaderboardResponse": { | |
| "properties": { | |
| "window": { | |
| "type": "string", | |
| "title": "Window" | |
| }, | |
| "token": { | |
| "type": "string", | |
| "title": "Token" | |
| }, | |
| "entries": { | |
| "items": { | |
| "$ref": "#/components/schemas/FunderEntry" | |
| }, | |
| "type": "array", | |
| "title": "Entries" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "window", | |
| "token", | |
| "entries" | |
| ], | |
| "title": "FundersLeaderboardResponse", | |
| "description": "Response model for funders leaderboard." | |
| }, | |
| "FundsTotalResponse": { | |
| "properties": { | |
| "token": { | |
| "type": "string", | |
| "title": "Token" | |
| }, | |
| "total_amount_usd": { | |
| "type": "string", | |
| "title": "Total Amount Usd" | |
| }, | |
| "total_amount_raw": { | |
| "type": "string", | |
| "title": "Total Amount Raw" | |
| }, | |
| "total_fund_count": { | |
| "type": "integer", | |
| "title": "Total Fund Count" | |
| }, | |
| "unique_account_count": { | |
| "type": "integer", | |
| "title": "Unique Account Count" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "token", | |
| "total_amount_usd", | |
| "total_amount_raw", | |
| "total_fund_count", | |
| "unique_account_count" | |
| ], | |
| "title": "FundsTotalResponse", | |
| "description": "Response model for aggregate funds total (the 'tipping jar')." | |
| }, | |
| "HTTPValidationError": { | |
| "properties": { | |
| "detail": { | |
| "items": { | |
| "$ref": "#/components/schemas/ValidationError" | |
| }, | |
| "type": "array", | |
| "title": "Detail" | |
| } | |
| }, | |
| "type": "object", | |
| "title": "HTTPValidationError" | |
| }, | |
| "LeaderboardEntry": { | |
| "properties": { | |
| "rank": { | |
| "type": "integer", | |
| "title": "Rank" | |
| }, | |
| "address": { | |
| "type": "string", | |
| "title": "Address" | |
| }, | |
| "account_id": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Account Id" | |
| }, | |
| "total_amount_usd": { | |
| "type": "string", | |
| "title": "Total Amount Usd" | |
| }, | |
| "total_amount_raw": { | |
| "type": "string", | |
| "title": "Total Amount Raw" | |
| }, | |
| "tip_count": { | |
| "type": "integer", | |
| "title": "Tip Count" | |
| }, | |
| "unique_counterparty_count": { | |
| "type": "integer", | |
| "title": "Unique Counterparty Count" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "rank", | |
| "address", | |
| "total_amount_usd", | |
| "total_amount_raw", | |
| "tip_count", | |
| "unique_counterparty_count" | |
| ], | |
| "title": "LeaderboardEntry", | |
| "description": "Entry in a tippers/tippees leaderboard.\n\nFor tippers: account_id is always set (must have Grove account to tip)\nFor tippees: account_id may be None if recipient doesn't have a Grove account\nFrontend should prefer account_id for display when available, fallback to address." | |
| }, | |
| "LeaderboardResponse": { | |
| "properties": { | |
| "window": { | |
| "type": "string", | |
| "title": "Window" | |
| }, | |
| "token": { | |
| "type": "string", | |
| "title": "Token" | |
| }, | |
| "entries": { | |
| "items": { | |
| "$ref": "#/components/schemas/LeaderboardEntry" | |
| }, | |
| "type": "array", | |
| "title": "Entries" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "window", | |
| "token", | |
| "entries" | |
| ], | |
| "title": "LeaderboardResponse", | |
| "description": "Response model for tippers/tippees leaderboard." | |
| }, | |
| "RecentTipEntry": { | |
| "properties": { | |
| "address": { | |
| "type": "string", | |
| "title": "Address" | |
| }, | |
| "account_id": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Account Id" | |
| }, | |
| "amount_usd": { | |
| "type": "string", | |
| "title": "Amount Usd" | |
| }, | |
| "amount_raw": { | |
| "type": "string", | |
| "title": "Amount Raw" | |
| }, | |
| "confirmed_at": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Confirmed At" | |
| }, | |
| "tx_hash": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Tx Hash" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "address", | |
| "amount_usd", | |
| "amount_raw" | |
| ], | |
| "title": "RecentTipEntry", | |
| "description": "Entry in a recent tips list.\n\nShows individual tip events ordered by most recent first.\nFor tippers: address is the sender's wallet\nFor tippees: address is the recipient's wallet" | |
| }, | |
| "RecentTipsResponse": { | |
| "properties": { | |
| "token": { | |
| "type": "string", | |
| "title": "Token" | |
| }, | |
| "entries": { | |
| "items": { | |
| "$ref": "#/components/schemas/RecentTipEntry" | |
| }, | |
| "type": "array", | |
| "title": "Entries" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "token", | |
| "entries" | |
| ], | |
| "title": "RecentTipsResponse", | |
| "description": "Response model for recent tips list." | |
| }, | |
| "RecoverRequest": { | |
| "properties": { | |
| "client_address": { | |
| "type": "string", | |
| "title": "Client Address" | |
| }, | |
| "signature": { | |
| "type": "string", | |
| "title": "Signature" | |
| }, | |
| "message": { | |
| "type": "string", | |
| "title": "Message" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "client_address", | |
| "signature", | |
| "message" | |
| ], | |
| "title": "RecoverRequest", | |
| "description": "Request payload for recovering an API key using the funding wallet signature." | |
| }, | |
| "RecoverResponse": { | |
| "properties": { | |
| "account_id": { | |
| "type": "string", | |
| "title": "Account Id" | |
| }, | |
| "api_key": { | |
| "type": "string", | |
| "title": "Api Key" | |
| }, | |
| "client_address": { | |
| "type": "string", | |
| "title": "Client Address" | |
| }, | |
| "onchain_address": { | |
| "type": "string", | |
| "title": "Onchain Address" | |
| }, | |
| "metadata": { | |
| "anyOf": [ | |
| { | |
| "additionalProperties": true, | |
| "type": "object" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Metadata" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "account_id", | |
| "api_key", | |
| "client_address", | |
| "onchain_address" | |
| ], | |
| "title": "RecoverResponse", | |
| "description": "Response payload for account recovery." | |
| }, | |
| "TipRequest": { | |
| "properties": { | |
| "destination": { | |
| "type": "string", | |
| "title": "Destination", | |
| "description": "Who to tip. Accepts multiple formats:\n- **EVM address**: `0x9ab39B84aC4DE6D705C5f051c07db8fE72890953`\n- **Solana address**: `9kucRUCUiYwJLDBBi5GXb4KeqgiRZ6uJeMdLwAuV6pUC`\n- **ENS name**: `vitalik.eth` (resolved via Ethereum mainnet)\n- **Domain**: `olshansky.info` (looks up address from llms.txt)\n- **Twitter/X**: `x.com/olshansky` or `@olshansky` (looks up address from bio)", | |
| "examples": [ | |
| "0x9ab39B84aC4DE6D705C5f051c07db8fE72890953", | |
| "olshansky.info", | |
| "x.com/olshansky" | |
| ] | |
| }, | |
| "amount": { | |
| "type": "string", | |
| "title": "Amount", | |
| "description": "Amount to tip. Supports multiple formats:\n- **Plain number**: `0.01` (uses token from query or DEFAULT_TOKEN)\n- **With currency**: `100USDC`, `0.5ETH`\n- **Dollar prefix**: `$1` (interpreted as 1 USDC)", | |
| "examples": [ | |
| "0.01", | |
| "100USDC", | |
| "$1" | |
| ] | |
| }, | |
| "network": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Network", | |
| "description": "Target blockchain network. Examples: `base`, `base-sepolia`, `solana-devnet`.\nDefaults to DEFAULT_NETWORK (base-sepolia) if not specified.", | |
| "examples": [ | |
| "base", | |
| "base-sepolia" | |
| ] | |
| }, | |
| "token": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "null" | |
| } | |
| ], | |
| "title": "Token", | |
| "description": "Token symbol to tip. Examples: `USDC`, `ETH`.\nDefaults to DEFAULT_TOKEN (USDC) if not specified.\n**Note**: If amount includes a token (e.g., `100USDC`) and this field specifies a different token, the request fails with 400.", | |
| "examples": [ | |
| "USDC", | |
| "ETH" | |
| ] | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "destination", | |
| "amount" | |
| ], | |
| "title": "TipRequest", | |
| "description": "Request body for JSON-based tipping via POST /v1/tip." | |
| }, | |
| "TipResponse": { | |
| "properties": { | |
| "tip_id": { | |
| "type": "string", | |
| "title": "Tip Id" | |
| }, | |
| "status": { | |
| "type": "string", | |
| "title": "Status" | |
| }, | |
| "destination": { | |
| "type": "string", | |
| "title": "Destination" | |
| }, | |
| "receiver_address": { | |
| "type": "string", | |
| "title": "Receiver Address" | |
| }, | |
| "amount_sent": { | |
| "type": "string", | |
| "title": "Amount Sent" | |
| }, | |
| "amount_received": { | |
| "type": "string", | |
| "title": "Amount Received" | |
| }, | |
| "fee_amount": { | |
| "type": "string", | |
| "title": "Fee Amount" | |
| }, | |
| "tx_hash": { | |
| "type": "string", | |
| "title": "Tx Hash" | |
| }, | |
| "new_balance": { | |
| "type": "string", | |
| "title": "New Balance" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "tip_id", | |
| "status", | |
| "destination", | |
| "receiver_address", | |
| "amount_sent", | |
| "amount_received", | |
| "fee_amount", | |
| "tx_hash", | |
| "new_balance" | |
| ], | |
| "title": "TipResponse", | |
| "description": "Response model for successful tip" | |
| }, | |
| "ValidationError": { | |
| "properties": { | |
| "loc": { | |
| "items": { | |
| "anyOf": [ | |
| { | |
| "type": "string" | |
| }, | |
| { | |
| "type": "integer" | |
| } | |
| ] | |
| }, | |
| "type": "array", | |
| "title": "Location" | |
| }, | |
| "msg": { | |
| "type": "string", | |
| "title": "Message" | |
| }, | |
| "type": { | |
| "type": "string", | |
| "title": "Error Type" | |
| } | |
| }, | |
| "type": "object", | |
| "required": [ | |
| "loc", | |
| "msg", | |
| "type" | |
| ], | |
| "title": "ValidationError" | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment