{"openapi":"3.0.0","paths":{"/api/v1/auth/handoff/create":{"post":{"description":"Called by auth.*.minmo.to after Hexclave sign-in. The response code is safe to place in a redirect URL; Hexclave tokens stay server-side until the origin app exchanges the code.","operationId":"createAuthHandoff","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAuthHandoffDto"}}}},"responses":{"201":{"description":"Auth handoff code created"},"400":{"description":"Invalid client or redirect URI"},"401":{"description":"Invalid Hexclave token"}},"security":[{"bearer":[]}],"summary":"Create a short-lived auth handoff code","tags":["auth"]}},"/api/v1/auth/handoff/exchange":{"post":{"description":"Called by console, mobile, or ops after auth.*.minmo.to redirects back with a code. Validates PKCE and returns the Mini-compatible Hexclave session material.","operationId":"exchangeAuthHandoff","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeAuthHandoffDto"}}}},"responses":{"200":{"description":"Auth handoff exchanged"},"400":{"description":"Invalid client or redirect URI"},"401":{"description":"Invalid or expired handoff code"},"409":{"description":"Local Mini profile is required"}},"summary":"Exchange a short-lived auth handoff code","tags":["auth"]}},"/api/v1/auth/hexclave/provision":{"post":{"description":"Verifies the hosted Minmo auth access token and creates the local Minmo user, auth identity, and optional agent profile for first-time wrapper-auth signup.","operationId":"provisionHexclaveUser","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HexclaveProvisionDto"}}}},"responses":{"201":{"description":"Local user provisioned or existing Hexclave identity found"},"400":{"description":"Invalid provisioning request"},"401":{"description":"Invalid Hexclave token"},"409":{"description":"Email already belongs to a user"}},"security":[{"bearer":[]}],"summary":"Provision local Minmo user after hosted auth signup","tags":["auth"]}},"/api/v1/auth/nostr/challenge":{"post":{"description":"Returns a one-time challenge string to be signed by the user's NOSTR key. Use the challenge with POST /auth/nostr/verify.","operationId":"getNostrChallenge","parameters":[],"responses":{"200":{"description":"Challenge generated","content":{"application/json":{"schema":{"type":"object","properties":{"challenge":{"type":"string"}}}}}}},"summary":"Get NOSTR login challenge","tags":["auth"]}},"/api/v1/auth/nostr/verify":{"post":{"description":"Verifies the NOSTR signature against the challenge, finds or creates the user, and returns an access token (same shape as login).","operationId":"verifyNostr","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NostrVerifyDto"}}}},"responses":{"200":{"description":"Sign-in successful","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"expires_in":{"type":"number"},"token_type":{"type":"string"},"user":{"type":"object"}}}}}},"400":{"description":"Invalid or expired challenge"},"401":{"description":"Invalid NOSTR signature"}},"summary":"Verify NOSTR signature and sign in","tags":["auth"]}},"/api/v1/auth/nostr/register":{"post":{"description":"Verifies NOSTR ownership using a challenge+event and creates a new NOSTR-backed user account. Optionally creates an agent profile using the same referral-gated flow as email registration.","operationId":"registerWithNostr","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NostrRegisterDto"}}}},"responses":{"200":{"description":"Registration successful","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"expires_in":{"type":"number"},"token_type":{"type":"string"},"user":{"type":"object"},"agent":{"type":"object","nullable":true}}}}}},"400":{"description":"Invalid or expired challenge"},"401":{"description":"Invalid NOSTR signature"}},"summary":"Register a new user with NOSTR","tags":["auth"]}},"/api/v1/auth/refresh":{"post":{"description":"Exchanges a Minmo Nostr or hosted Minmo auth refresh token for a new access token","operationId":"refreshToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshTokenDto"}}}},"responses":{"200":{"description":"Token refreshed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"expires_in":{"type":"number"},"token_type":{"type":"string"}}}}}},"401":{"description":"Invalid refresh token"}},"summary":"Refresh access token","tags":["auth"]}},"/api/v1/auth/me":{"get":{"description":"Returns provider-neutral current-user information after the active authentication guard resolves the request to a local Mini user.","operationId":"getCurrentUser","parameters":[],"responses":{"200":{"description":"Current authenticated user"},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Get current authenticated Mini user","tags":["auth"]},"patch":{"description":"Update the authenticated user's profile (email and/or name). Only provided fields are updated.","operationId":"patchMe","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchMeDto"}}}},"responses":{"200":{"description":"Profile updated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"metadata":{"type":"object"},"status":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Update current user profile","tags":["auth"]}},"/api/v1/auth/me/deletion-request":{"post":{"description":"\n      Records a request to delete the authenticated user's account. Deletion\n      itself stays an admin action against DELETE /users/:id; this only queues\n      the request for the team to act on.\n\n      The account stays active and usable while the request is outstanding so\n      the user can still withdraw a remaining balance. Re-requesting returns the\n      standing request rather than creating a second one.\n    ","operationId":"requestAccountDeletion","parameters":[],"responses":{"201":{"description":"Deletion request recorded"},"401":{"description":"Unauthorized"},"403":{"description":"Account is not an agent account"}},"security":[{"bearer":[]}],"summary":"Request deletion of the current account","tags":["auth"]}},"/api/v1/auth/nostr-identity/private-key":{"get":{"description":"Returns the current user's Nostr private key in nsec backup form when the identity is operator-custodied. Every export attempt is persisted in the Nostr identity export audit trail.","operationId":"exportNostrIdentityPrivateKey","parameters":[],"responses":{"200":{"description":"Nostr private key export returned","content":{"application/json":{"schema":{"type":"object","properties":{"pubkeyHex":{"type":"string"},"npub":{"type":"string"},"nsec":{"type":"string"},"custodyMode":{"type":"string"},"exportedAt":{"type":"string","format":"date-time"},"exportCount":{"type":"number"}}}}}},"400":{"description":"Private key is not exportable"},"401":{"description":"Unauthorized"}},"security":[{"bearer":[]}],"summary":"Export the current user's Nostr private key","tags":["auth"]}},"/api/v1/teams/{id}/referral-code":{"get":{"operationId":"getReferralCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get the active team referral code","tags":["teams"]},"patch":{"operationId":"updateReferralCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamReferralCodeDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update the active team referral code policy","tags":["teams"]}},"/api/v1/teams/{id}/referral-codes":{"get":{"operationId":"listReferralCodes","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"includeRevoked","required":false,"in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List team referral codes","tags":["teams"]},"post":{"operationId":"createReferralCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamReferralCodeDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Create a team referral code","tags":["teams"]}},"/api/v1/teams/{id}/referral-codes/{codeId}":{"delete":{"operationId":"revokeReferralCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"codeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"summary":"Revoke a team referral code","tags":["teams"]}},"/api/v1/teams/{id}/referral-code/rotate":{"post":{"operationId":"rotateReferralCode","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotateTeamReferralCodeDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Rotate the active team referral code","tags":["teams"]}},"/api/v1/teams":{"get":{"operationId":"listTeams","parameters":[{"name":"query","required":false,"in":"query","description":"Free-text search over team display name or exact team ID","schema":{"type":"string"}},{"name":"cursor","required":false,"in":"query","description":"Pagination cursor returned by the previous page","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of teams to return","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List Hexclave teams for Minmo administration","tags":["teams"]},"post":{"operationId":"createTeam","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Create a Hexclave team","tags":["teams"]}},"/api/v1/teams/invitations/accept":{"post":{"operationId":"acceptInvitation","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptTeamInvitationDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Accept a Hexclave team invitation by code","tags":["teams"]}},"/api/v1/teams/{id}":{"get":{"operationId":"getTeam","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get team detail, members, and invitations","tags":["teams"]},"patch":{"operationId":"updateTeam","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update team profile fields","tags":["teams"]}},"/api/v1/teams/{id}/currency-settings":{"get":{"operationId":"getTeamCurrencySettings","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get team currency settings","tags":["teams"]},"patch":{"operationId":"updateTeamCurrencySettings","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamCurrencySettingsDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update team currency settings","tags":["teams"]}},"/api/v1/teams/{id}/descriptors/{descriptorId}/escrow-fee-policy":{"get":{"operationId":"getEscrowFeePolicy","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"descriptorId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get team escrow fee policy","tags":["teams"]},"patch":{"operationId":"updateEscrowFeePolicy","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"descriptorId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateEscrowFeePolicyDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update team escrow fee policy","tags":["teams"]}},"/api/v1/teams/{id}/features":{"get":{"operationId":"listTeamFeatures","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List team console features","tags":["teams"]}},"/api/v1/teams/{id}/features/{featureId}":{"get":{"operationId":"getTeamFeature","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"featureId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a team console feature","tags":["teams"]},"patch":{"description":"A feature can only be enabled if the team's plan entitles it to. Granting access a plan does not include is an entitlement override, not a feature flag.","operationId":"updateTeamFeature","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"featureId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFeatureDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update a team console feature","tags":["teams"]}},"/api/v1/teams/{id}/members":{"post":{"operationId":"addMember","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTeamMemberDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Add a local Minmo user to a team","tags":["teams"]}},"/api/v1/teams/{id}/invitations":{"post":{"operationId":"inviteMember","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteTeamMemberDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Invite a user to a team by email","tags":["teams"]}},"/api/v1/teams/{id}/nostr-identity/private-key":{"post":{"operationId":"revealTeamNostrPrivateKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Reveal a team's managed Nostr private key","tags":["teams"]}},"/api/v1/teams/{id}/members/{userId}":{"delete":{"operationId":"removeMember","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Remove a user from a team","tags":["teams"]}},"/api/v1/teams/{id}/members/{userId}/roles":{"patch":{"operationId":"updateMemberRoles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"userId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamMemberRolesDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Assign team-scoped Minmo roles to a member","tags":["teams"]}},"/api/v1/teams/{id}/api-keys":{"post":{"operationId":"createTeamApiKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTeamApiKeyDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Create a team API key","tags":["teams"]}},"/api/v1/teams/{id}/api-keys/{apiKeyId}":{"delete":{"operationId":"revokeTeamApiKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"apiKeyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Revoke a team API key","tags":["teams"]}},"/api/v1/teams/{id}/api-keys/{apiKeyId}/policy":{"patch":{"operationId":"updateTeamApiKeyPolicy","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"apiKeyId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTeamApiKeyPolicyDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update a team API key resource policy","tags":["teams"]}},"/api/v1/fx/rates/{baseCurrency}/{targetCurrency}":{"get":{"description":"Retrieve the current exchange rate between two currencies.\n\n    **Rate Sources:**\n    - Multiple data providers aggregated\n    - Real-time market rates\n    - Cached for performance (5-minute TTL)\n    - Fallback sources for reliability\n\n    **Supported Pairs:**\n    - All major fiat currencies\n    - Bitcoin (BTC) to fiat\n    - Cross-rates calculated automatically\n    - Updated every minute\n\n    **Rate Calculation:**\n    - Weighted average of multiple sources\n    - Confidence scoring based on variance and number of sources\n    - Fallback to indirect and cached rates\n\n    **Performance:**\n    - Average response time < 50ms\n    - 99.9% availability SLA\n    - Automatic failover\n    - Rate limiting: 100 req/min","operationId":"getFxRate","parameters":[{"name":"baseCurrency","required":true,"in":"path","description":"Base currency code (from currency)","schema":{"enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"type":"string"}},{"name":"targetCurrency","required":true,"in":"path","description":"Target currency code (to currency)","schema":{"enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"type":"string"}}],"responses":{"200":{"description":"FX rate retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FxRateResponse"}}}},"400":{"description":"Bad request - Invalid currency pair or unsupported currencies"},"404":{"description":"Not found - FX rate not available for this pair"},"429":{"description":"Too many requests - Rate limit exceeded"},"503":{"description":"Service unavailable - FX service temporarily unavailable"}},"security":[{"bearer":[]}],"summary":"Get FX rate for a currency pair","tags":["fx"]}},"/api/v1/fx/rates/{baseCurrency}/{targetCurrency}/detailed":{"get":{"description":"Retrieve comprehensive FX rate information including all data sources and confidence metrics.\n\n    **Detailed Information:**\n    - Rate from each individual source\n    - Aggregated weighted average rate\n    - Confidence score (0-100)\n    - Source timestamps\n    - Variance metrics\n    - Historical comparison\n\n    **Source Providers:**\n    - CoinGecko API\n    - Binance Exchange\n    - CoinMarketCap\n    - Local bank rates (fiat)\n    - Weighted by reliability\n\n    **Confidence Calculation:**\n    - Based on source agreement\n    - Time since last update\n    - Historical volatility\n    - Number of sources\n\n    **Use Cases:**\n    - Rate transparency\n    - Audit requirements\n    - Source debugging\n    - Rate validation","operationId":"getDetailedFxRate","parameters":[{"name":"baseCurrency","required":true,"in":"path","description":"Base currency code (from currency)","schema":{"enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"type":"string"}},{"name":"targetCurrency","required":true,"in":"path","description":"Target currency code (to currency)","schema":{"enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"type":"string"}}],"responses":{"200":{"description":"Detailed FX rate with source breakdown retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AggregatedFxRateResponse"}}}},"400":{"description":"Bad request - Invalid currency pair"},"503":{"description":"Service unavailable - Unable to fetch from sources"}},"security":[{"bearer":[]}],"summary":"Get detailed aggregated FX rate with all sources","tags":["fx"]}},"/api/v1/fx/rates/{baseCurrency}/{targetCurrency}/historical":{"get":{"operationId":"getHistoricalFxRate","parameters":[{"name":"baseCurrency","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetCurrency","required":true,"in":"path","schema":{"type":"string"}},{"name":"date","required":true,"in":"query","description":"Completed UTC calendar day (YYYY-MM-DD)","schema":{"example":"2026-09-01","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoricalFxRateResponse"}}}}},"security":[{"bearer":[]}],"summary":"Get a historical market valuation for a completed UTC day","tags":["fx"]}},"/api/v1/fx/supported-pairs":{"get":{"description":"Retrieve all currency pairs supported by the FX service.\n\n    **Pair Categories:**\n    - Fiat to Fiat (USD/EUR, etc.)\n    - Crypto to Fiat (BTC/USD, etc.)\n    - All combinations available\n    - Bidirectional support\n\n    **Response Format:**\n    - Array of pair strings\n    - Format: \"BASE/TARGET\"\n    - Sorted alphabetically\n    - Updated dynamically\n\n    **Supported Currencies:**\n    - USD (US Dollar)\n    - KES (Kenyan Shilling)\n    - BTC (Bitcoin)\n\n    **Updates:**\n    - New pairs added automatically\n    - Deprecated pairs removed\n    - Check regularly for changes","operationId":"getSupportedPairs","parameters":[],"responses":{"200":{"description":"List of supported currency pairs retrieved successfully","schema":{"type":"object","properties":{"pairs":{"type":"array","items":{"type":"string"},"example":["BTC/USD","BTC/KES","USD/KES","EUR/USD"]},"total":{"type":"number","example":56}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportedPairsResponse"}}}}},"security":[{"bearer":[]}],"summary":"Get list of supported currency pairs","tags":["fx"]}},"/api/v1/fx/health":{"get":{"description":"Check the operational status of all FX rate data sources.\n\n    **Health Checks:**\n    - API connectivity\n    - Response time\n    - Data freshness\n    - Error rates\n    - Rate limits\n\n    **Source Status:**\n    - healthy: Operating normally\n    - degraded: Slow or partial data\n    - unhealthy: Failed or unavailable\n    - disabled: Manually turned off\n\n    **Metrics Included:**\n    - Last successful fetch\n    - Average response time\n    - Success rate (24h)\n    - Current rate limit status\n\n    **Monitoring:**\n    - Real-time health checks\n    - Automatic failover\n    - Alert thresholds\n    - Historical tracking","operationId":"getFxHealthStatus","parameters":[],"responses":{"200":{"description":"Health status of all FX sources retrieved successfully","schema":{"type":"object","properties":{"healthy":{"type":"boolean","example":true,"description":"Overall system health"},"sources":{"type":"object","properties":{"coingecko":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","unhealthy"],"example":"healthy"},"enabled":{"type":"boolean","example":true},"lastCheck":{"type":"string","format":"date-time"},"responseTime":{"type":"number","example":245,"description":"Response time in ms"},"successRate":{"type":"number","example":99.8,"description":"Success rate percentage"}}}}},"timestamp":{"type":"string","format":"date-time"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatusResponse"}}}}},"security":[{"bearer":[]}],"summary":"Get health status of all FX rate sources","tags":["fx"]}},"/api/v1/fx/admin/cache/metrics":{"get":{"description":"Retrieve detailed metrics about the FX rate cache performance.\n\n    **Cache Metrics:**\n    - Total entries in cache\n    - Cache hit/miss ratio\n    - Memory usage\n    - Stale entries count\n    - Average entry age\n\n    **Performance Metrics:**\n    - Cache response time\n    - Refresh frequency\n    - Eviction statistics\n    - Storage efficiency\n\n    **Monitoring:**\n    - Real-time statistics\n    - Historical trends\n    - Alert thresholds\n    - Optimization suggestions\n\n    **Admin Features:**\n    - Requires FX_RATES_MANAGE permission\n    - Detailed debugging info\n    - Cache tuning parameters","operationId":"getCacheMetrics","parameters":[],"responses":{"200":{"description":"Cache metrics retrieved successfully","schema":{"type":"object","properties":{"totalEntries":{"type":"number","example":150,"description":"Total cache entries"},"fxCacheEntries":{"type":"number","example":120,"description":"FX rate specific entries"},"staleCacheEntries":{"type":"number","example":5,"description":"Entries needing refresh"},"hitRate":{"type":"number","example":94.5,"description":"Cache hit rate percentage"},"memoryUsageMB":{"type":"number","example":12.5,"description":"Memory usage in MB"},"averageEntryAgeSeconds":{"type":"number","example":180,"description":"Average age of entries"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CacheMetricsResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - Insufficient permissions (requires FX_RATES_MANAGE)"}},"security":[{"bearer":[]}],"summary":"Get FX rate cache metrics (Admin)","tags":["fx"]}},"/api/v1/fx/admin/cache/clear":{"post":{"description":"Clear all cached FX rates forcing fresh data retrieval.\n\n    **Cache Clear Effects:**\n    - All cached rates removed\n    - Next requests fetch fresh data\n    - Temporary performance impact\n    - Sources re-queried\n\n    **Use Cases:**\n    - Resolve stale data issues\n    - Force immediate updates\n    - Testing and debugging\n    - After configuration changes\n\n    **Important Notes:**\n    - May cause rate limit issues\n    - Increases response time temporarily\n    - Affects all users\n    - Logged for audit\n\n    **Best Practices:**\n    - Use sparingly\n    - Preferably during low traffic\n    - Monitor after clearing\n    - Consider selective clear instead","operationId":"clearCache","parameters":[],"responses":{"200":{"description":"Cache cleared successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"FX rate cache cleared successfully"},"entriesCleared":{"type":"number","example":150},"timestamp":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - Insufficient permissions (requires FX_RATES_MANAGE)"}},"security":[{"bearer":[]}],"summary":"Clear FX rate cache (Admin)","tags":["fx"]}},"/api/v1/fx/admin/cache/preload":{"post":{"description":"Preload frequently used FX rates into cache for optimal performance.\n\n    **Preload Strategy:**\n    - Most common currency pairs\n    - High-volume corridors\n    - All BTC pairs\n    - Major fiat crosses\n\n    **Pairs Preloaded:**\n    - BTC to all fiat currencies\n    - USD to all currencies\n    - Regional popular pairs\n    - Approximately 30-40 pairs\n\n    **Benefits:**\n    - Improved response times\n    - Reduced source queries\n    - Better user experience\n    - Load distribution\n\n    **Execution:**\n    - Async background process\n    - Progress tracking available\n    - Respects rate limits\n    - Skips recently cached\n\n    **Best Practices:**\n    - Run during off-peak hours\n    - After cache clear\n    - Daily scheduled job\n    - Monitor completion","operationId":"preloadCache","parameters":[],"responses":{"200":{"description":"Cache preload initiated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Common FX rates preloaded successfully"},"pairsLoaded":{"type":"number","example":35},"duration":{"type":"number","example":2500,"description":"Time taken in milliseconds"},"timestamp":{"type":"string","format":"date-time"}}}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - Insufficient permissions (requires FX_RATES_MANAGE)"},"503":{"description":"Service unavailable - FX sources temporarily unavailable"}},"security":[{"bearer":[]}],"summary":"Preload common FX rates (Admin)","tags":["fx"]}},"/api/v1/teams/{teamId}/fx/source-config":{"get":{"operationId":"getSourceConfig","parameters":[{"name":"teamId","required":true,"in":"path","description":"Team ID","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get team FX rate source configuration","tags":["team-fx"]},"patch":{"operationId":"updateSourceConfig","parameters":[{"name":"teamId","required":true,"in":"path","description":"Team ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePartnerFxRateSourcesDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update team FX rate source configuration","tags":["team-fx"]}},"/api/v1/teams/{teamId}/fx/rates/quote":{"get":{"operationId":"getQuote","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"baseCurrency","required":true,"in":"query","schema":{"type":"string"}},{"name":"targetCurrency","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a partner-scoped OTC rate quote","tags":["team-fx"]}},"/api/v1/teams/{teamId}/fx/display-rates":{"get":{"operationId":"getDisplayRates","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get the team wallet display-rate snapshot","tags":["team-fx"]}},"/api/v1/teams/{teamId}/fx/rates/{baseCurrency}/{targetCurrency}/detailed":{"get":{"operationId":"getTeamDetailedFxRate","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"baseCurrency","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetCurrency","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get team-configured detailed FX rate","tags":["team-fx"]}},"/api/v1/teams/{teamId}/fx/rates/{baseCurrency}/{targetCurrency}/historical":{"get":{"operationId":"getHistoricalFxRate","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"baseCurrency","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetCurrency","required":true,"in":"path","schema":{"type":"string"}},{"name":"date","required":true,"in":"query","description":"Completed UTC calendar day (YYYY-MM-DD)","schema":{"example":"2026-09-01","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoricalFxRateResponse"}}}}},"security":[{"bearer":[]}],"summary":"Get a dated market valuation using the Partner's current source policy","tags":["team-fx"]}},"/api/v1/teams/{teamId}/fx/health":{"get":{"operationId":"getTeamFxHealthStatus","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get team-configured FX source health","tags":["team-fx"]}},"/api/v1/teams/{teamId}/swaps/disputed":{"get":{"operationId":"listTeamDisputedSwaps","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/swaps":{"get":{"operationId":"listTeamSwaps","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"minimum":1,"default":"1","example":"1","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":100,"default":"10","example":"10","type":"string"}},{"name":"segment","required":false,"in":"query","description":"Filter by open or terminal swap lifecycle segment","schema":{"$ref":"#/components/schemas/SwapListSegment"}},{"name":"state","required":false,"in":"query","description":"Filter by swap state","schema":{"$ref":"#/components/schemas/SwapState"}},{"name":"type","required":false,"in":"query","description":"Filter by swap type","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"reference","required":false,"in":"query","description":"Filter by swap reference","schema":{"pattern":"^[A-Z0-9-]+$","example":"SWAP-2024-001234","type":"string"}},{"name":"id","required":false,"in":"query","description":"Filter by swap ID (supports partial UUID matching)","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}},{"name":"agentId","required":false,"in":"query","description":"Filter by agent ID","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}},{"name":"beneficiaryId","required":false,"in":"query","description":"Filter by beneficiary Nostr public key.","schema":{"pattern":"^[0-9a-fA-F]{64}$","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","type":"string"}},{"name":"currency","required":false,"in":"query","description":"Filter by currency code (ISO 4217)","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"startDate","required":false,"in":"query","description":"Include swaps created at or after this ISO 8601 timestamp","schema":{"format":"date-time","example":"2026-08-01T00:00:00.000Z","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Include swaps created at or before this ISO 8601 timestamp","schema":{"format":"date-time","example":"2026-08-24T23:59:59.999Z","type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/swaps/{swapId}/dispute":{"get":{"operationId":"getTeamDispute","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"swapId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/swaps/{swapId}/dispute-resolution":{"patch":{"operationId":"resolveTeamDispute","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"swapId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveDisputeDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/swaps/{swapId}/cancel":{"patch":{"operationId":"cancelTeamSwap","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"swapId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelSwapDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/swaps/{swapId}/repair":{"post":{"operationId":"repairTeamSwap","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"swapId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RepairSwapDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/swaps/{swapId}":{"get":{"operationId":"getTeamSwap","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"swapId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/escrow/reconcile":{"post":{"operationId":"reconcileTeamEscrow","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/teams/{teamId}/escrow/{reference}/reconcile-swap":{"post":{"operationId":"reconcileSwapFromEscrow","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReconcileSwapBody"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["swap"]}},"/api/v1/swap/quote":{"get":{"operationId":"quote","parameters":[{"name":"agentId","required":true,"in":"query","schema":{"type":"string"}},{"name":"fiatCurrency","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a partner-scoped OTC swap quote","tags":["swap"]}},"/api/v1/swap":{"get":{"description":"Retrieve a paginated list of swaps with automatic access control.\n\n    **Access Control**:\n    - **Agents/Users**: Returns swaps where they are involved:\n      - As beneficiary (swaps they created)\n      - As agent owner (swaps assigned to their agent profile)\n    - **Admins** (with SWAP_READ_ALL permission): Returns all swaps in the system\n\n    **Filtering**: All query parameters (agentId, beneficiaryId, state, etc.) work for both user types.\n    Admins can filter across all swaps, while agents can only filter within their own swaps.","operationId":"listSwaps","parameters":[{"name":"page","required":false,"in":"query","description":"Page number for pagination","schema":{"minimum":1,"default":"1","example":"1","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page","schema":{"minimum":1,"maximum":100,"default":"10","example":"20","type":"string"}},{"name":"segment","required":false,"in":"query","description":"Filter by open or terminal swap lifecycle segment","schema":{"$ref":"#/components/schemas/SwapListSegment"}},{"name":"state","required":false,"in":"query","description":"Filter by swap state","schema":{"$ref":"#/components/schemas/SwapState"}},{"name":"type","required":false,"in":"query","description":"Filter by swap type","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"reference","required":false,"in":"query","description":"Filter by swap reference","schema":{"pattern":"^[A-Z0-9-]+$","example":"SWAP-2024-001234","type":"string"}},{"name":"id","required":false,"in":"query","description":"Filter by swap ID (supports partial UUID matching)","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}},{"name":"agentId","required":false,"in":"query","description":"Filter by agent ID","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}},{"name":"beneficiaryId","required":false,"in":"query","description":"Filter by beneficiary Nostr public key (admin only)","schema":{"pattern":"^[0-9a-fA-F]{64}$","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","type":"string"}},{"name":"currency","required":false,"in":"query","description":"Filter by currency","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"startDate","required":false,"in":"query","description":"Include swaps created at or after this timestamp","schema":{"format":"date-time","example":"2026-08-01T00:00:00.000Z","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Include swaps created at or before this timestamp","schema":{"format":"date-time","example":"2026-08-24T23:59:59.999Z","type":"string"}}],"responses":{"200":{"description":"Successfully retrieved swaps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedSwapsResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - Insufficient permissions for requested operation"}},"security":[{"bearer":[]}],"summary":"List swaps","tags":["swap"]},"post":{"description":"Create a new cryptocurrency swap with dual-mode agent selection:\n\n      **Direct Selection Mode:**\n      - Provide 'agentId' to select a specific agent\n      - Swap is saved with the selected agent context in 'created' state\n      - Escrow creation happens when the agent claims, so wallet liquidity is not required to create the quote\n\n      **Auto-Selection Mode:**\n      - Omit 'agentId' for automatic agent matching\n      - Swap remains in 'created' state for agents to claim\n      - Traditional agent discovery and claiming process\n\n      **Authentication:**\n      - 'beneficiaryId' must be supplied by the swap requester\n      - For new swaps, 'beneficiaryId' is the requester's Nostr public key, not a local Minmo user ID","operationId":"createSwap","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSwapDto"}}}},"responses":{"201":{"description":"Swap created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Invalid swap data or agent validation failed"}},"security":[{"bearer":[]}],"summary":"Create a new swap","tags":["swap"]}},"/api/v1/swap/disputed":{"get":{"description":"Retrieve all swaps currently in dispute status requiring arbitration. Admin only.","operationId":"listDisputedSwaps","parameters":[],"responses":{"200":{"description":"Successfully retrieved disputed swaps","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SwapResponse"}}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - Admin permissions required"}},"security":[{"bearer":[]}],"summary":"List disputed swaps","tags":["swap"]}},"/api/v1/swap/agent/{agentId}/escrow-status":{"get":{"description":"Retrieve the aggregate active onramp escrow exposure for a specific agent.","operationId":"getAgentOnrampEscrowStatus","parameters":[{"name":"agentId","required":true,"in":"path","description":"Unique identifier of the agent","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Agent onramp escrow status retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string"},"totalEscrowSats":{"type":"string"},"swaps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"state":{"type":"string"},"bitcoinAmountSats":{"type":"string"},"fees":{"type":"object"},"escrowAmountSats":{"type":"string"}}}}}}}}}},"security":[{"bearer":[]}],"summary":"Get agent onramp escrow status","tags":["swap"]}},"/api/v1/swap/agent/{agentId}":{"get":{"description":"Retrieve swaps for a specific agent.\n\n    **Access Control**:\n    - Users can only access swaps for agents they own\n    - Returns swaps assigned to the agent profile","operationId":"listAgentSwaps","parameters":[{"name":"agentId","required":true,"in":"path","description":"Unique identifier of the agent","schema":{"format":"uuid","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"minimum":1,"default":"1","example":"1","type":"string"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"minimum":1,"maximum":100,"default":"10","example":"10","type":"string"}},{"name":"segment","required":false,"in":"query","description":"Filter by open or terminal swap lifecycle segment","schema":{"$ref":"#/components/schemas/SwapListSegment"}},{"name":"state","required":false,"in":"query","description":"Filter by state","schema":{"$ref":"#/components/schemas/SwapState"}},{"name":"type","required":false,"in":"query","description":"Filter by swap type","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"reference","required":false,"in":"query","description":"Filter by swap reference","schema":{"pattern":"^[A-Z0-9-]+$","example":"SWAP-2024-001234","type":"string"}},{"name":"id","required":false,"in":"query","description":"Filter by swap ID (supports partial UUID matching)","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}},{"name":"beneficiaryId","required":false,"in":"query","description":"Filter by beneficiary Nostr public key.","schema":{"pattern":"^[0-9a-fA-F]{64}$","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","type":"string"}},{"name":"currency","required":false,"in":"query","description":"Filter by currency code (ISO 4217)","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"startDate","required":false,"in":"query","description":"Include swaps created at or after this ISO 8601 timestamp","schema":{"format":"date-time","example":"2026-08-01T00:00:00.000Z","type":"string"}},{"name":"endDate","required":false,"in":"query","description":"Include swaps created at or before this ISO 8601 timestamp","schema":{"format":"date-time","example":"2026-08-24T23:59:59.999Z","type":"string"}}],"responses":{"200":{"description":"Successfully retrieved agent's swaps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedSwapsResponse"}}}},"401":{"description":"Unauthorized"},"403":{"description":"Forbidden - User does not own this agent"},"404":{"description":"Agent not found"}},"security":[{"bearer":[]}],"summary":"List agent's swaps","tags":["swap"]}},"/api/v1/swap/agent/{agentId}/disputes":{"get":{"description":"Retrieve all disputes for a specific agent. Admin only.","operationId":"getAgentDisputes","parameters":[{"name":"agentId","required":true,"in":"path","description":"Agent ID","schema":{"format":"uuid","type":"string"}},{"name":"state","required":false,"in":"query","description":"Filter by dispute state","schema":{"enum":["created","agent_matched","escrow_pending","escrow_locked","payment_instructed","payment_pending","payment_submitted","payment_confirmed_user","payment_confirmed_agent","confirmation_pending","completed","cancelled","refund_initiated","refund_failed","disputed","dispute_evidence_collection","dispute_internal_review","dispute_resolved","dispute_review","refunded","expired","fiat_sender_timeout","fiat_receiver_timeout","transferred_to_backup"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Items per page","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number","schema":{"type":"number"}}],"responses":{"200":{"description":"Agent dispute history retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedSwapsResponse"}}}},"404":{"description":"Agent not found"}},"security":[{"bearer":[]}],"summary":"Get agent dispute history","tags":["swap"]}},"/api/v1/swap/agent/{agentId}/dispute-stats":{"get":{"description":"Retrieve dispute statistics for an agent. Admin only.","operationId":"getAgentDisputeStats","parameters":[{"name":"agentId","required":true,"in":"path","description":"Agent ID","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Agent dispute statistics retrieved","content":{"application/json":{"schema":{"type":"object","properties":{"totalDisputes":{"type":"number"},"activeDisputes":{"type":"number"},"resolvedDisputes":{"type":"number"},"userWins":{"type":"number"},"agentWins":{"type":"number"},"splits":{"type":"number"},"resolutionRate":{"type":"number"},"averageResolutionTime":{"type":"number"}}}}}},"404":{"description":"Agent not found"}},"security":[{"bearer":[]}],"summary":"Get agent dispute statistics","tags":["swap"]}},"/api/v1/swap/{id}":{"get":{"description":"Retrieve detailed information about a specific swap.\n\n    **Authentication Required**: Users can only view swaps they are involved in (as beneficiary or agent) unless they have admin permissions.","operationId":"getSwap","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the swap","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Swap details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Get swap details","tags":["swap"]}},"/api/v1/swap/{id}/escrow-status":{"get":{"description":"Retrieves the payment status of the Lightning escrow invoice for a given onramp swap.\n    This endpoint is used by clients to poll for payment confirmation before an agent claims the swap.","operationId":"getEscrowStatus","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the swap","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Escrow payment status retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"swapId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["PENDING","PROCESSING","COMPLETE","FAILED","EXPIRED","CANCELLED"]},"paymentHash":{"type":"string"},"invoice":{"type":"string"}}}}}},"403":{"description":"Forbidden - Not authorized to access this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Get escrow payment status for an onramp swap","tags":["swap"]}},"/api/v1/swap/{id}/claim":{"post":{"description":"Allows an agent to claim an available swap. The swap must be in 'created' state.","operationId":"claimSwap","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID to claim","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":false,"description":"Optional Lightning invoice information. Required when claiming OFFRAMP swaps so we know how to pay the agent, unless the agent has a Lightning address configured in their settings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapClaimDto"}}}},"responses":{"200":{"description":"Swap claimed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Swap already claimed or agent not eligible"},"403":{"description":"User does not have an agent profile"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Claim a swap as an agent","tags":["swap"]}},"/api/v1/swap/{id}/verify-escrow":{"post":{"description":"Verifies that the escrow invoice has been fully paid. For ONRAMP swaps, requires agent authorization. For OFFRAMP swaps, requires beneficiary authorization.","operationId":"verifyEscrowFunding","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID to verify escrow for","schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"description":"Escrow verified successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Escrow not funded or invalid swap state"},"403":{"description":"Not authorized to verify escrow for this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Verify escrow funding for a swap","tags":["swap"]}},"/api/v1/swap/{id}/confirm":{"patch":{"description":"Confirm that payment has been sent (for user) or received (for agent).","operationId":"confirmSwap","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"description":"Confirmation details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmSwapDto"}}}},"responses":{"200":{"description":"Payment confirmed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Invalid confirmation or swap state"},"403":{"description":"Not authorized to confirm this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Confirm payment for a swap","tags":["swap"]}},"/api/v1/swap/{id}/cancel":{"patch":{"description":"Cancel an active swap. Only possible before payment confirmations.\n\n    **Access Control**:\n    - **Users/Agents**: Can cancel swaps where they are participant (beneficiary or agent owner)\n    - **Admins** (with SWAP_CANCEL_ALL): Can cancel any swap","operationId":"cancelSwap","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID to cancel","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":false,"description":"Cancel details (optional)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelSwapDto"}}}},"responses":{"200":{"description":"Swap cancelled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Cannot cancel swap in current state"},"403":{"description":"Not authorized to cancel this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Cancel a swap","tags":["swap"]}},"/api/v1/swap/{id}/dispute":{"post":{"description":"Initiate a dispute for a swap when there's a disagreement about payment.","operationId":"disputeSwap","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID to dispute","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"description":"Dispute details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DisputeSwapDto"}}}},"responses":{"200":{"description":"Dispute initiated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Cannot dispute swap in current state"},"403":{"description":"Not authorized to dispute this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Dispute a swap","tags":["swap"]}},"/api/v1/swap/{id}/payment-proof":{"post":{"description":"Submit proof of payment such as transaction receipts or confirmation codes.","operationId":"submitPaymentProof","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"description":"Payment proof details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitPaymentProofDto"}}}},"responses":{"200":{"description":"Payment proof submitted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Invalid proof format or swap state"},"403":{"description":"Not authorized to submit proof for this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Submit payment proof for a swap","tags":["swap"]}},"/api/v1/swap/{id}/dispute-evidence":{"post":{"description":"Submit additional evidence during the dispute resolution process.","operationId":"submitDisputeEvidence","parameters":[{"name":"id","required":true,"in":"path","description":"Disputed swap ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"description":"Evidence details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmitDisputeEvidenceDto"}}}},"responses":{"200":{"description":"Evidence submitted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Swap not in evidence collection phase"},"403":{"description":"Not authorized to submit evidence for this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Submit evidence for a disputed swap","tags":["swap"]}},"/api/v1/swap/{id}/execute-refund":{"post":{"description":"Executes a Bitcoin refund for a swap in REFUND_INITIATED state. Requires a Lightning invoice or on-chain Bitcoin address as destination.","operationId":"executeRefund","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID to execute refund for","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"description":"Refund destination details. Must be a valid Lightning invoice or Bitcoin on-chain address.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteRefundDto"}}}},"responses":{"200":{"description":"Refund executed successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Invalid state or refund destination"},"403":{"description":"Not authorized to execute refund for this swap"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Execute BTC refund for a swap","tags":["swap"]}},"/api/v1/swap/{id}/resolve-dispute":{"patch":{"description":"Record the operator decision on the authoritative escrow after reviewing evidence. Money movement remains an explicit release or refund operation. Swaps without an escrow record use the compatibility settlement path. Admin/Arbitrator only.","operationId":"resolveDispute","parameters":[{"name":"id","required":true,"in":"path","description":"Disputed swap ID","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"description":"Resolution details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveDisputeDto"}}}},"responses":{"200":{"description":"Dispute decision recorded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Swap not in dispute state"},"403":{"description":"Insufficient permissions"},"404":{"description":"Swap not found"}},"security":[{"bearer":[]}],"summary":"Resolve a disputed swap","tags":["swap"]}},"/api/v1/swap/{id}/transfer":{"patch":{"description":"Transfer an active swap from one agent to another. Admin only.","operationId":"transferSwap","parameters":[{"name":"id","required":true,"in":"path","description":"Swap ID to transfer","schema":{"format":"uuid","type":"string"}}],"requestBody":{"required":true,"description":"Transfer details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferSwapDto"}}}},"responses":{"200":{"description":"Swap transferred successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SwapResponse"}}}},"400":{"description":"Cannot transfer swap in current state"},"403":{"description":"Insufficient permissions"},"404":{"description":"Swap or agent not found"}},"security":[{"bearer":[]}],"summary":"Transfer swap to another agent","tags":["swap"]}},"/api/v1/spec":{"get":{"description":"Returns the complete OpenAPI 3.0 specification for the Minmo API.\n\n    **Specification Contents:**\n    - All API endpoints with full documentation\n    - Request/response schemas\n    - Authentication requirements\n    - Data models and DTOs\n    - Error response formats\n    - Example values\n\n    **OpenAPI Features:**\n    - Version 3.0 compliant\n    - Interactive documentation available at /api-docs\n    - Code generation support\n    - Postman/Insomnia import compatible\n    - Mock server generation\n\n    **API Sections:**\n    - Authentication (auth)\n    - Agent Management (agents)\n    - Swap Operations (swap)\n    - Bitcoin/Lightning (bitcoin)\n    - Liquidity Management (liquidity)\n    - FX Rates (fx)\n    - Health Monitoring (health)\n\n    **Usage:**\n    - Import into API testing tools\n    - Generate client SDKs\n    - API documentation\n    - Contract testing\n    - Mock development\n\n    **Updates:**\n    - Automatically generated from code\n    - Always up-to-date\n    - Version controlled\n    - Breaking changes documented","operationId":"getOpenApiSpec","parameters":[],"responses":{"200":{"description":"OpenAPI specification returned successfully","content":{"application/json":{"schema":{"type":"object","properties":{"openapi":{"type":"string","example":"3.0.0"},"info":{"type":"object","properties":{"title":{"type":"string","example":"Minmo API"},"description":{"type":"string","example":"P2P Bitcoin exchange platform API"},"version":{"type":"string","example":"2.0.0"},"contact":{"type":"object","properties":{"name":{"type":"string","example":"Minmo Support"},"email":{"type":"string","example":"support@minmo.io"},"url":{"type":"string","example":"https://minmo.io"}}},"license":{"type":"object","properties":{"name":{"type":"string","example":"Proprietary"},"url":{"type":"string","example":"https://minmo.io/terms"}}}}},"servers":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","example":"https://api.minmo.io"},"description":{"type":"string","example":"Production server"}}}},"paths":{"type":"object","description":"All API endpoints"},"components":{"type":"object","properties":{"schemas":{"type":"object","description":"Data models"},"securitySchemes":{"type":"object","description":"Authentication methods"}}},"tags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}}}}}}}}}},"summary":"Get OpenAPI specification","tags":["documentation"]}},"/api/v1/agents/discovery":{"get":{"description":"Returns active, publicly visible agent summaries for swap matching. This endpoint is intentionally separate from authenticated agent management.","operationId":"discoverAgents","parameters":[{"name":"currency","required":false,"in":"query","description":"Currency to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"paymentChannel","required":false,"in":"query","description":"Payment channel to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/PaymentChannel"}},{"name":"amount","required":false,"in":"query","description":"Transaction amount in satoshis to filter agents by min/max limits","schema":{"pattern":"^[0-9]+$","example":"100000","type":"string"}},{"name":"type","required":false,"in":"query","description":"Swap type for margin optimization","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"status","required":false,"in":"query","description":"Filter by agent status (admin only)","schema":{"$ref":"#/components/schemas/AgentStatus"}},{"name":"isAutomated","required":false,"in":"query","description":"Filter by whether agent is automated. Automated agents are not currently supported.","schema":{"example":false,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search agents by agent ID, user email, name, hex pubkey, or npub","schema":{"example":"agent@example.com","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (default: 20, max: 100 for admin, 50 for public)","schema":{"minimum":1,"maximum":100,"example":20,"type":"number"}}],"responses":{"200":{"description":"Available agents retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAgentsResponse"}}}}},"summary":"Discover available public agents","tags":["agent-discovery"]}},"/api/v1/agents/register":{"post":{"description":"Register a new agent in the system. This endpoint supports both self-registration and admin registration.\n\n    **Self-Registration:**\n    - Users register themselves as agents\n    - userId field is optional (uses authenticated user's ID)\n    - Requires authentication token\n\n    **Admin Registration:**\n    - Admins can register other users as agents\n    - Provide userId to register a specific user\n    - Requires admin privileges\n\n    **Agent Capabilities:**\n    - Support multiple currencies and payment channels\n    - Set transaction limits and margins\n    - Configure operating hours","operationId":"register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterAgentDto"}}}},"responses":{"201":{"description":"Agent registered successfully - Returns complete agent profile with ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"400":{"description":"Bad request - Invalid registration data or validation failed"},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"409":{"description":"Conflict - Agent profile already exists for this user"}},"security":[{"bearer":[]}],"summary":"Register as an agent","tags":["agents"]}},"/api/v1/agents/{id}/team-referral":{"post":{"description":"Applies a team-scoped referral code to the authenticated agent profile. Swap links should remain hidden until this creates an active team association.","operationId":"activateTeamReferral","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateAgentTeamReferralDto"}}}},"responses":{"200":{"description":"Agent team association activated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}}},"security":[{"bearer":[]}],"summary":"Activate an agent team association with a referral code","tags":["agents"]}},"/api/v1/agents/{id}/availability":{"put":{"description":"Update an agent's availability status to control whether they can accept new swaps.\n\n    **Status Options:**\n    - ACTIVE: Agent is available and can accept swaps\n    - BUSY: Agent is temporarily unavailable\n    - INACTIVE: Agent is offline and cannot accept swaps\n\n    **Impact:**\n    - ACTIVE agents appear in search results and can claim swaps\n    - BUSY agents complete existing swaps but don't accept new ones\n    - INACTIVE agents are hidden from all operations\n\n    **Access Control:**\n    - Agents can update their own availability\n    - Admins can update any agent's availability","operationId":"updateAvailability","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the agent to update","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAvailabilityDto"}}}},"responses":{"200":{"description":"Availability updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - Cannot update another agent's availability without ownership or admin privileges"},"404":{"description":"Not found - Agent not found"}},"security":[{"bearer":[]}],"summary":"Update agent availability status","tags":["agents"]}},"/api/v1/agents/{id}/validate":{"post":{"description":"Validate whether a specific agent can handle a swap with the given parameters before creating the swap. This endpoint performs comprehensive validation including:\n\n**Validation Checks:**\n- Agent exists and is active\n- Agent supports the specified currency and payment channel\n- Amount is within agent's transaction limits (min/max)\n- Agent has sufficient available liquidity\n- Agent is currently accepting swaps\n\n**Usage Flow:**\n1. Discover agents using /agents/discovery\n2. Validate specific agent before swap creation\n3. Create swap with validated agent ID\n\n**Error Scenarios:**\n- Agent not found or inactive\n- Currency/channel not supported\n- Amount outside transaction limits\n- Insufficient liquidity\n- Agent temporarily unavailable\n\n**Performance:**\n- Fast validation using cached agent data\n- Real-time liquidity checks\n- Immediate response with detailed error messages","operationId":"validateAgentForSwap","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateAgentDto"}}}},"responses":{"200":{"description":"Agent validation successful - agent can handle the swap","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"400":{"description":"Agent validation failed"},"404":{"description":"Agent not found"}},"security":[{"bearer":[]}],"summary":"Validate agent for direct swap selection","tags":["agents"]}},"/api/v1/agents/stats":{"get":{"description":"Retrieve comprehensive statistics and performance metrics for the authenticated agent.\n\n    **Metrics Included:**\n    - Total completed swaps\n    - Success rate percentage\n    - Average completion time\n    - Total volume processed\n    - Volume by currency\n    - Volume by swap type (onramp/offramp)\n    - Daily, weekly, monthly trends\n    - Current rating and reviews\n    - Active swaps count\n    - Liquidity utilization\n\n    **Time Periods:**\n    - Real-time current statistics\n    - Historical data for trend analysis\n    - Comparative metrics vs platform average","operationId":"getStats","parameters":[],"responses":{"200":{"description":"Agent statistics retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"completedSwaps":{"type":"number","example":150},"successRate":{"type":"number","example":98.5},"averageCompletionTime":{"type":"number","example":45,"description":"Minutes"},"totalVolume":{"type":"number","example":1000000},"volumeByCurrency":{"type":"object","example":{"USD":500000,"KES":300000}},"volumeByType":{"type":"object","example":{"onramp":600000,"offramp":400000}},"currentRating":{"type":"number","example":4.8},"activeSwaps":{"type":"number","example":3},"liquidityUtilization":{"type":"number","example":65.5}}}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"404":{"description":"Not found - Agent profile not found for authenticated user"}},"security":[{"bearer":[]}],"summary":"Get agent statistics","tags":["agents"]}},"/api/v1/agents":{"get":{"description":"Retrieve agent resources the authenticated caller can manage or inspect.\n\n**Platform admins:**\n- Returns the platform-wide agent collection.\n- Supports management filters such as status, automation, and search.\n\n**Agent owners:**\n- Returns the caller's own local agent profile when present.\n\nPublic swap matching and lightweight discovery use /agents/discovery instead.","operationId":"getAgents","parameters":[{"name":"currency","required":false,"in":"query","description":"Currency to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"paymentChannel","required":false,"in":"query","description":"Payment channel to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/PaymentChannel"}},{"name":"amount","required":false,"in":"query","description":"Transaction amount in satoshis to filter agents by min/max limits","schema":{"pattern":"^[0-9]+$","example":"100000","type":"string"}},{"name":"type","required":false,"in":"query","description":"Swap type for margin optimization","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"status","required":false,"in":"query","description":"Filter by agent status (admin only)","schema":{"$ref":"#/components/schemas/AgentStatus"}},{"name":"isAutomated","required":false,"in":"query","description":"Filter by whether agent is automated. Automated agents are not currently supported.","schema":{"example":false,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search agents by agent ID, user email, name, hex pubkey, or npub","schema":{"example":"agent@example.com","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (default: 20, max: 100 for admin, 50 for public)","schema":{"minimum":1,"maximum":100,"example":20,"type":"number"}}],"responses":{"200":{"description":"List of agents retrieved with role-based data","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAgentsResponse"}}}},"400":{"description":"Invalid query parameters"},"401":{"description":"Unauthorized - Admin access requires authentication"},"403":{"description":"Forbidden - Admin access requires MINMO_ADMIN role"}},"security":[{"bearer":[]}],"summary":"Get manageable agents for the authenticated caller","tags":["agents"]}},"/api/v1/agents/{id}":{"get":{"description":"Retrieve detailed information about a specific agent.\n\n    **Information Included:**\n    - Agent profile and configuration\n    - Supported currencies and payment channels\n    - Transaction limits and margin rates\n    - Performance metrics and rating\n    - Operating hours and availability\n    - Liquidity status\n    - Automation settings (if applicable)\n\n    **Access Control:**\n    - Public endpoint for basic agent information\n    - Sensitive details may be restricted based on user role","operationId":"getAgent","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the agent","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}}],"responses":{"200":{"description":"Agent details retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"400":{"description":"Bad request - Invalid agent ID format"},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"404":{"description":"Not found - Agent with specified ID does not exist"}},"security":[{"bearer":[]}],"summary":"Get agent by ID","tags":["agents"]},"put":{"description":"Update an agent's configuration and settings.\n\n    **Updatable Fields:**\n    - Supported currencies and payment channels\n    - Transaction limits (min/max amounts)\n    - Margin rates for onramp/offramp\n    - Operating hours and availability windows\n    - Contact information and preferences\n\n    **Access Control:**\n    - Agents can update their own profile\n    - Admins can update any agent profile\n    - Some fields may require admin privileges\n\n    **Validation:**\n    - Currency codes must be valid\n    - Limits must be positive numbers\n    - Margin rates must be reasonable (0-10000 basis points)\n    - Operating hours must be valid time ranges","operationId":"updateAgent","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the agent to update","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAgentDto"}}}},"responses":{"200":{"description":"Agent configuration updated successfully - Returns updated agent profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}},"400":{"description":"Bad request - Invalid update data or validation failed"},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - Insufficient permissions to update this agent"},"404":{"description":"Not found - Agent with specified ID does not exist"}},"security":[{"bearer":[]}],"summary":"Update agent configuration","tags":["agents"]},"delete":{"description":"Deactivate an agent profile, preventing them from accepting new swaps.\n\n    **Deactivation Effects:**\n    - Agent status set to INACTIVE\n    - Cannot claim or be assigned new swaps\n    - Existing swaps continue to completion\n    - Profile hidden from search results\n    - Liquidity released after swap completion\n\n    **Access Control:**\n    - Agents can only deactivate their own profile\n    - Admins may have override capabilities\n    - Deactivation is reversible through status update\n\n    **Important:**\n    - Complete all active swaps before deactivation\n    - Withdraw any remaining liquidity\n    - Update dependent systems if applicable","operationId":"deactivateAgent","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the agent to deactivate","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}}],"responses":{"200":{"description":"Agent deactivated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Agent profile deactivated successfully"},"agentId":{"type":"string","example":"550e8400-e29b-41d4-a716-446655440000"}}}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - You can only deactivate your own agent profile"},"404":{"description":"Not found - Agent with specified ID does not exist"},"409":{"description":"Conflict - Cannot deactivate agent with active swaps"}},"security":[{"bearer":[]}],"summary":"Deactivate an agent","tags":["agents"]}},"/api/v1/agents/{id}/swaps":{"get":{"description":"Retrieve paginated swap history for a specific agent.\n\n    **Information Included:**\n    - Swap details (ID, reference, type, state)\n    - Transaction amounts and currencies\n    - Counterparty information\n    - Timestamps (created, claimed, completed)\n    - Payment details and confirmations\n    - Dispute status if applicable\n\n    **Filtering Options:**\n    - Filter by swap state\n    - Pagination support\n    - Sorted by most recent first\n\n    **Use Cases:**\n    - Agent transaction history\n    - Performance analysis\n    - Dispute resolution\n    - Audit trail","operationId":"getAgentSwaps","parameters":[{"name":"id","required":true,"in":"path","description":"Unique identifier of the agent","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}},{"name":"state","required":false,"in":"query","description":"Filter by swap state","schema":{"enum":["created","agent_matched","escrow_pending","escrow_locked","payment_instructed","payment_pending","payment_submitted","payment_confirmed_user","payment_confirmed_agent","confirmation_pending","completed","cancelled","refund_initiated","refund_failed","disputed","dispute_evidence_collection","dispute_internal_review","dispute_resolved","dispute_review","refunded","expired","fiat_sender_timeout","fiat_receiver_timeout","transferred_to_backup"],"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Items per page (default: 20)","schema":{"type":"number"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"type":"number"}}],"responses":{"200":{"description":"Agent trade history retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentSwapHistoryResponse"}}}},"404":{"description":"Agent not found"}},"security":[{"bearer":[]}],"summary":"Get agent swap history","tags":["agents"]}},"/api/v1/teams/{teamId}/agents":{"get":{"description":"Returns team-facing summaries for agents with an active primary association to the selected team.","operationId":"getTeamAgents","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"currency","required":false,"in":"query","description":"Currency to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"paymentChannel","required":false,"in":"query","description":"Payment channel to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/PaymentChannel"}},{"name":"amount","required":false,"in":"query","description":"Transaction amount in satoshis to filter agents by min/max limits","schema":{"pattern":"^[0-9]+$","example":"100000","type":"string"}},{"name":"type","required":false,"in":"query","description":"Swap type for margin optimization","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"status","required":false,"in":"query","description":"Filter by agent status (admin only)","schema":{"$ref":"#/components/schemas/AgentStatus"}},{"name":"isAutomated","required":false,"in":"query","description":"Filter by whether agent is automated. Automated agents are not currently supported.","schema":{"example":false,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search agents by agent ID, user email, name, hex pubkey, or npub","schema":{"example":"agent@example.com","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (default: 20, max: 100 for admin, 50 for public)","schema":{"minimum":1,"maximum":100,"example":20,"type":"number"}}],"responses":{"200":{"description":"Team agents retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PaginatedAgentsResponse"}}}}},"security":[{"bearer":[]}],"summary":"List agents associated with a team","tags":["team-agents"]}},"/api/v1/teams/{teamId}/agents/{agentId}":{"get":{"description":"Returns a team-facing agent summary only when the agent has an active, team-visible primary association with the selected team.","operationId":"getTeamAgent","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"agentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Team agent retrieved successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}}},"security":[{"bearer":[]}],"summary":"Get a team-scoped agent summary","tags":["team-agents"]}},"/api/v1/teams/{teamId}/agents/{agentId}/availability":{"put":{"description":"Allows a team manager to activate or deactivate an agent with an active primary association to the selected team.","operationId":"updateTeamAgentAvailability","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"agentId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateAvailabilityDto"}}}},"responses":{"200":{"description":"Team agent availability updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}}},"security":[{"bearer":[]}],"summary":"Update availability for an agent in a team","tags":["team-agents"]}},"/api/v1/teams/{teamId}/agents/{agentId}/association":{"put":{"description":"Associates an agent with a primary Mini team without changing agent ownership.","operationId":"setTeamAssociation","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"agentId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAgentTeamAssociationDto"}}}},"responses":{"200":{"description":"Agent team association updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}}},"security":[{"bearer":[]}],"summary":"Set an agent's primary team association","tags":["team-agents"]},"delete":{"description":"Marks an agent's primary association as removed without deleting the agent.","operationId":"removeTeamAssociation","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"agentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Agent team association removed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponse"}}}}},"security":[{"bearer":[]}],"summary":"Remove an agent's primary team association","tags":["team-agents"]}},"/api/v1/agent-activity":{"get":{"description":"Returns a bounded dashboard aggregate of agents, recent swaps, and metrics across the platform.","operationId":"getPlatformActivity","parameters":[{"name":"currency","required":false,"in":"query","description":"Currency to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"paymentChannel","required":false,"in":"query","description":"Payment channel to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/PaymentChannel"}},{"name":"amount","required":false,"in":"query","description":"Transaction amount in satoshis to filter agents by min/max limits","schema":{"pattern":"^[0-9]+$","example":"100000","type":"string"}},{"name":"type","required":false,"in":"query","description":"Swap type for margin optimization","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"status","required":false,"in":"query","description":"Filter by agent status (admin only)","schema":{"$ref":"#/components/schemas/AgentStatus"}},{"name":"isAutomated","required":false,"in":"query","description":"Filter by whether agent is automated. Automated agents are not currently supported.","schema":{"example":false,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search agents by agent ID, user email, name, hex pubkey, or npub","schema":{"example":"agent@example.com","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (default: 20, max: 100 for admin, 50 for public)","schema":{"minimum":1,"maximum":100,"example":20,"type":"number"}}],"responses":{"200":{"description":"Platform agent activity retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentActivityResponse"}}}}},"security":[{"bearer":[]}],"summary":"Get platform-scoped agent activity","tags":["agent-activity"]}},"/api/v1/teams/{teamId}/agent-activity":{"get":{"description":"Returns a bounded dashboard aggregate of team-affiliated agents, recent attributed swaps, and team metrics.","operationId":"getTeamActivity","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"currency","required":false,"in":"query","description":"Currency to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/Currency"}},{"name":"paymentChannel","required":false,"in":"query","description":"Payment channel to filter agents by (public discovery)","schema":{"$ref":"#/components/schemas/PaymentChannel"}},{"name":"amount","required":false,"in":"query","description":"Transaction amount in satoshis to filter agents by min/max limits","schema":{"pattern":"^[0-9]+$","example":"100000","type":"string"}},{"name":"type","required":false,"in":"query","description":"Swap type for margin optimization","schema":{"$ref":"#/components/schemas/SwapType"}},{"name":"status","required":false,"in":"query","description":"Filter by agent status (admin only)","schema":{"$ref":"#/components/schemas/AgentStatus"}},{"name":"isAutomated","required":false,"in":"query","description":"Filter by whether agent is automated. Automated agents are not currently supported.","schema":{"example":false,"type":"boolean"}},{"name":"search","required":false,"in":"query","description":"Search agents by agent ID, user email, name, hex pubkey, or npub","schema":{"example":"agent@example.com","type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (default: 1)","schema":{"minimum":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Items per page (default: 20, max: 100 for admin, 50 for public)","schema":{"minimum":1,"maximum":100,"example":20,"type":"number"}}],"responses":{"200":{"description":"Team agent activity retrieved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentActivityResponse"}}}}},"security":[{"bearer":[]}],"summary":"Get team-scoped agent activity","tags":["agent-activity"]}},"/api/v1/liquidity/agent/{agentId}":{"get":{"description":"Retrieve comprehensive liquidity information for a specific agent.\n\n    **Profile Information:**\n    - Total declared liquidity per currency\n    - Available liquidity (not locked in swaps)\n    - Locked liquidity (reserved for active swaps)\n    - Declared balances from external wallets (BTC and fiat)\n\n    **Currency Support:**\n    - All supported fiat currencies (USD, KES, etc.)\n    - Bitcoin (BTC) from external wallets\n    - Declaration-based approach for all currencies\n\n    **Use Cases:**\n    - Agent dashboard display\n    - Swap matching decisions\n    - Liquidity reporting\n    - Risk assessment\n\n    **Access Control:**\n    - Agents can view own liquidity\n    - Admins can view any agent's liquidity\n    - Public access restricted","operationId":"getAgentLiquidity","parameters":[{"name":"agentId","required":true,"in":"path","description":"Unique identifier of the agent","schema":{"format":"uuid","example":"550e8400-e29b-41d4-a716-446655440000","type":"string"}}],"responses":{"200":{"description":"Agent liquidity profile retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","format":"uuid"},"liquidity":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string","enum":["BTC","USD","KES","NGN","ZAR","GHS"]},"total":{"type":"string","example":"100000"},"available":{"type":"string","example":"75000"},"locked":{"type":"string","example":"25000"},"isCustodial":{"type":"boolean","example":false}}}},"lastSyncedAt":{"type":"string","format":"date-time"},"totalValueUSD":{"type":"number","example":150000}}}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token"},"403":{"description":"Forbidden - Insufficient permissions to view this agent's liquidity"},"404":{"description":"Not found - Agent with specified ID does not exist"}},"security":[{"bearer":[]}],"summary":"Get agent liquidity profile","tags":["liquidity"]}},"/api/v1/liquidity/validate":{"post":{"operationId":"validateLiquidity","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateLiquidityDto"}}}},"responses":{"200":{"description":"Liquidity validation result"}},"security":[{"bearer":[]}],"summary":"Validate liquidity for a swap","tags":["liquidity"]}},"/api/v1/liquidity/agent/{agentId}/history":{"get":{"operationId":"getHistory","parameters":[{"name":"agentId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"currency","required":false,"in":"query","description":"Filter by currency","schema":{"enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"type":"string"}},{"name":"changeType","required":false,"in":"query","description":"Filter by change type","schema":{"enum":["deposit","withdrawal","swap_reserved","swap_completed","swap_cancelled","manual_adjustment","custodial_sync","declaration"],"type":"string"}},{"name":"startDate","required":false,"in":"query","description":"Start date (ISO 8601)","schema":{"type":"string"}},{"name":"endDate","required":false,"in":"query","description":"End date (ISO 8601)","schema":{"type":"string"}},{"name":"limit","required":false,"in":"query","description":"Number of records to return","schema":{"type":"number"}},{"name":"offset","required":false,"in":"query","description":"Number of records to skip","schema":{"type":"number"}}],"responses":{"200":{"description":"Liquidity history retrieved successfully"}},"security":[{"bearer":[]}],"summary":"Get liquidity history for an agent","tags":["liquidity"]}},"/api/v1/liquidity/agent/{agentId}/report":{"get":{"operationId":"generateLiquidityReport","parameters":[{"name":"agentId","required":true,"in":"path","schema":{"format":"uuid","type":"string"}},{"name":"startDate","required":true,"in":"query","description":"Report start date (ISO 8601)","schema":{"type":"string"}},{"name":"endDate","required":true,"in":"query","description":"Report end date (ISO 8601)","schema":{"type":"string"}}],"responses":{"200":{"description":"Liquidity report generated successfully"},"400":{"description":"Invalid date range"}},"security":[{"bearer":[]}],"summary":"Generate liquidity report for an agent","tags":["liquidity"]}},"/api/v1/teams/{teamId}/escrows":{"post":{"operationId":"createEscrow","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]},"get":{"operationId":"listEscrows","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}},{"name":"offset","required":true,"in":"query","schema":{"type":"string"}},{"name":"statuses","required":true,"in":"query","schema":{"type":"string"}},{"name":"reference","required":true,"in":"query","schema":{"type":"string"}},{"name":"terminal","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/activity":{"get":{"operationId":"listEscrowActivity","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"openLimit","required":true,"in":"query","schema":{"type":"string"}},{"name":"openOffset","required":true,"in":"query","schema":{"type":"string"}},{"name":"openStatuses","required":true,"in":"query","schema":{"type":"string"}},{"name":"openReference","required":true,"in":"query","schema":{"type":"string"}},{"name":"historyLimit","required":true,"in":"query","schema":{"type":"string"}},{"name":"historyOffset","required":true,"in":"query","schema":{"type":"string"}},{"name":"historyStatuses","required":true,"in":"query","schema":{"type":"string"}},{"name":"historyReference","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}":{"get":{"operationId":"getEscrow","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/payout-status":{"get":{"operationId":"getEscrowPayoutStatus","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/audit":{"get":{"operationId":"getEscrowAudit","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/funding/verify":{"post":{"operationId":"verifyTeamFunding","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/funding/mock-complete":{"post":{"operationId":"markTeamMockFundingComplete","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/expire":{"post":{"operationId":"expireUnfundedEscrow","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/release":{"post":{"operationId":"releaseEscrow","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/refund":{"post":{"operationId":"refundEscrow","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/escrows/{reference}/dispute-resolution":{"post":{"operationId":"recordTeamDisputeResolution","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/descriptors":{"get":{"operationId":"getTeamDescriptorById","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]},"patch":{"operationId":"updateTeamDescriptorById","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/descriptors/publish":{"post":{"operationId":"publishTeamDescriptorById","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/descriptors/wallet":{"patch":{"operationId":"updateTeamDescriptorWallet","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Escrow"]}},"/api/v1/teams/{teamId}/wallets":{"get":{"operationId":"listTeamWallets","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]},"post":{"operationId":"createTeamWallet","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}":{"get":{"operationId":"getTeamWallet","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]},"patch":{"operationId":"updateTeamWallet","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]},"delete":{"operationId":"deleteTeamWallet","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/connections":{"get":{"operationId":"listTeamWalletConnections","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]},"post":{"operationId":"createTeamWalletConnection","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWalletConnectionDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/connections/{connectionId}":{"delete":{"operationId":"revokeTeamWalletConnection","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/bitcoin/receive":{"post":{"operationId":"createTeamBitcoinReceiveRequest","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/bitcoin/overview":{"get":{"operationId":"getTeamBitcoinWalletOverview","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/bitcoin/history":{"get":{"operationId":"getTeamBitcoinWalletHistory","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/bitcoin/deposits/{txid}/{vout}/claim":{"post":{"operationId":"claimTeamBitcoinWalletDeposit","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}},{"name":"txid","required":true,"in":"path","schema":{"type":"string"}},{"name":"vout","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/stable-balance/stabilize":{"post":{"operationId":"stabilizeTeamWalletBalance","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/bitcoin/payouts/{reference}":{"get":{"operationId":"getTeamBitcoinPayoutStatus","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}},{"name":"reference","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/bitcoin/send":{"post":{"operationId":"sendTeamBitcoinPayment","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/payout-quote":{"post":{"operationId":"quoteTeamBitcoinPayout","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/bitcoin/transfer":{"post":{"operationId":"transferBetweenTeamWallets","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/teams/{teamId}/wallets/{walletId}/seed/reveal":{"post":{"operationId":"revealTeamSeed","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"walletId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Wallet"]}},"/api/v1/wallet-connection/info":{"get":{"operationId":"getWalletConnectionInfo","parameters":[],"responses":{"200":{"description":""}},"tags":["Wallet"]}},"/api/v1/wallet-connection/balance":{"get":{"operationId":"getWalletConnectionBalance","parameters":[],"responses":{"200":{"description":""}},"tags":["Wallet"]}},"/api/v1/wallet-connection/invoices":{"post":{"operationId":"createWalletConnectionInvoice","parameters":[],"responses":{"201":{"description":""}},"tags":["Wallet"]}},"/api/v1/wallet-connection/invoices/{invoiceId}":{"get":{"operationId":"getWalletConnectionInvoice","parameters":[{"name":"invoiceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Wallet"]}},"/api/v1/wallet-connection/payments/{paymentHash}":{"get":{"operationId":"getWalletConnectionPayment","parameters":[{"name":"paymentHash","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Wallet"]}},"/api/v1/wallet-connection/invoices/pay":{"post":{"operationId":"rejectWalletConnectionPayment","parameters":[],"responses":{"201":{"description":""}},"tags":["Wallet"]}},"/api/v1/integrations/pay/stores":{"get":{"operationId":"listStores[0]","parameters":[{"name":"partnerId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]},"post":{"operationId":"createStore[0]","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePayStoreDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/partners/{partnerId}/integrations/pay/stores":{"get":{"operationId":"listStores[1]","parameters":[{"name":"partnerId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]},"post":{"operationId":"createStore[1]","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePayStoreDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/integrations/pay/stores/{storeId}":{"get":{"operationId":"getStore[0]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/partners/{partnerId}/integrations/pay/stores/{storeId}":{"get":{"operationId":"getStore[1]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/integrations/pay/stores/{storeId}/connect-wallet":{"post":{"operationId":"connectWallet[0]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectPayWalletDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/partners/{partnerId}/integrations/pay/stores/{storeId}/connect-wallet":{"post":{"operationId":"connectWallet[1]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectPayWalletDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/integrations/pay/stores/{storeId}/invoices":{"post":{"operationId":"createInvoice[0]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}},{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Unique key for safely retrying invoice creation","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePayInvoiceDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/partners/{partnerId}/integrations/pay/stores/{storeId}/invoices":{"post":{"operationId":"createInvoice[1]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}},{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Unique key for safely retrying invoice creation","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePayInvoiceDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/integrations/pay/stores/{storeId}/invoices/{invoiceId}":{"get":{"operationId":"getInvoice[0]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}},{"name":"invoiceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/partners/{partnerId}/integrations/pay/stores/{storeId}/invoices/{invoiceId}":{"get":{"operationId":"getInvoice[1]","parameters":[{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}},{"name":"invoiceId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Pay"]}},"/api/v1/partners/{partnerId}/integrations/pay/stores/{storeId}/webhook":{"post":{"operationId":"receiveWebhook","parameters":[{"name":"partnerId","required":true,"in":"path","schema":{"type":"string"}},{"name":"storeId","required":true,"in":"path","schema":{"type":"string"}},{"name":"btcpay-sig","required":true,"in":"header","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"tags":["Pay"]}},"/api/v1/teams/{teamId}/analytics":{"get":{"operationId":"getTeamAnalytics","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"bucket","required":true,"in":"query","schema":{"type":"string"}},{"name":"feature","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Analytics"]}},"/api/v1/analytics":{"get":{"operationId":"getSystemAnalytics","parameters":[{"name":"bucket","required":true,"in":"query","schema":{"type":"string"}},{"name":"feature","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Analytics"]}},"/api/v1/teams/{teamId}/overview":{"get":{"operationId":"getPartnerOverview","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"tags":["Overview"]}},"/api/v1/referral/verify":{"post":{"description":"Verify if a referral code is valid and active. \n    This endpoint is public and does not require authentication.\n    It only checks validity, does not consume the code.","operationId":"verifyCode","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyReferralCodeDto"}}}},"responses":{"200":{"description":"Verification result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyReferralCodeResponse"}}}}},"summary":"Verify a referral code (public)","tags":["referral"]}},"/api/v1/system/referral-codes":{"get":{"operationId":"list","parameters":[{"name":"includeRevoked","required":false,"in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"List system referral codes","tags":["system referral codes"]},"post":{"operationId":"create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReferralCodeDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Create a system referral code","tags":["system referral codes"]}},"/api/v1/system/referral-codes/{id}":{"get":{"operationId":"get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a system referral code","tags":["system referral codes"]},"delete":{"operationId":"revoke","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]}],"summary":"Revoke a system referral code","tags":["system referral codes"]}},"/api/v1/events/stream":{"get":{"description":"Streams typed MinmoEvent envelopes for the authenticated principal and optional beneficiary ID.","operationId":"stream","parameters":[{"name":"beneficiaryId","required":false,"in":"query","description":"Only stream OTC events addressed to this beneficiary.","schema":{"type":"string"}},{"name":"partnerId","required":true,"in":"query","schema":{"type":"string"}},{"name":"storeId","required":false,"in":"query","description":"Only stream Pay events scoped to this store.","schema":{"type":"string"}},{"name":"aggregateId","required":true,"in":"query","schema":{"type":"string"}},{"name":"last-event-id","required":true,"in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Stream authorized Minmo events","tags":["Events"]}},"/api/v1/events/push-tokens":{"post":{"operationId":"registerPushToken","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterPushTokenDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Register a push notification token","tags":["Events"]},"delete":{"operationId":"removeAllPushTokens","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Remove all push tokens for the authenticated user","tags":["Events"]}},"/api/v1/events/push-tokens/{token}":{"delete":{"operationId":"removePushToken","parameters":[{"name":"token","required":true,"in":"path","description":"Push notification token","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Remove a push notification token","tags":["Events"]}},"/api/v1/events/push-tokens/{token}/refresh":{"post":{"operationId":"refreshPushToken","parameters":[{"name":"token","required":true,"in":"path","description":"Push notification token","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Refresh a push notification token","tags":["Events"]}},"/api/v1/teams/{teamId}/accounting/reporting-templates":{"get":{"operationId":"listReportingTemplates","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List saved reporting templates","tags":["Accounting & Reporting"]},"post":{"operationId":"createReportingTemplate","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReportingTemplateDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Save a reporting template","tags":["Accounting & Reporting"]}},"/api/v1/teams/{teamId}/accounting/reporting-templates/{templateId}":{"delete":{"operationId":"removeReportingTemplate","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"templateId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"204":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Delete a reporting template","tags":["Accounting & Reporting"]}},"/api/v1/teams/{teamId}/accounting/reports/generic-csv":{"post":{"operationId":"generateAccountingReport","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAccountingReportDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Generate an uncertified one-time accounting CSV","tags":["Accounting & Reporting"]}},"/api/v1/teams/{teamId}/accounting/sources":{"get":{"operationId":"listSources","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"type","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Discover authorized accounting Sources","tags":["Accounting & Reporting"]}},"/api/v1/psp/providers/{provider}/callbacks/{endpointId}":{"post":{"operationId":"receiveProviderCallback","parameters":[{"name":"provider","required":true,"in":"path","schema":{"type":"string"}},{"name":"endpointId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[],"summary":"Receive a PSP provider callback","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/providers":{"get":{"operationId":"listProviders","parameters":[],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List available PSP provider definitions","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/providers/{provider}":{"get":{"operationId":"getProvider","parameters":[{"name":"provider","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Get an available PSP provider definition","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections":{"get":{"operationId":"listConnections","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List a Partner's PSP connections","tags":["PSP integrations"]},"post":{"operationId":"createConnection","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOwnerPspConnectionDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Create an encrypted PSP connection draft","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections/{connectionId}":{"get":{"operationId":"getConnection","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Get a Partner PSP connection","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections/{connectionId}/activate":{"post":{"operationId":"activateConnection","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Validate and activate a PSP connection","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections/{connectionId}/credentials":{"put":{"operationId":"rotateCredentials","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RotatePspCredentialsDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Validate and rotate PSP credentials","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections/{connectionId}/delegations":{"post":{"operationId":"createDelegation","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDelegatedPspConnectionDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Authorize a Partner Agent to use a PSP connection","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections/{connectionId}/revoke":{"post":{"operationId":"revokeDelegation","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokePspConnectionDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Revoke delegated PSP access","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections/{connectionId}/collections":{"post":{"operationId":"createCollection","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}},{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Unique key for safely retrying this collection request","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePspCollectionDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Initiate a PSP collection","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/connections/{connectionId}/disbursements":{"post":{"operationId":"createDisbursement","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"connectionId","required":true,"in":"path","schema":{"type":"string"}},{"name":"idempotency-key","required":true,"in":"header","schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","description":"Unique key for safely retrying this disbursement request","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePspDisbursementDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Initiate a PSP disbursement","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/payments/{paymentId}":{"get":{"operationId":"getPayment","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"paymentId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Get normalized PSP payment state","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/payments":{"get":{"operationId":"listPayments","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List normalized PSP payments","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/accounts":{"get":{"operationId":"listAccounts","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List internal PSP subledger accounts","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/accounts/{accountId}":{"get":{"operationId":"getAccount","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"accountId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Get an internal PSP subledger account","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/liquidity":{"get":{"operationId":"listLiquidity","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List internally attributed PSP balances","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/accounts/{accountId}/statement":{"get":{"operationId":"getAccountStatement","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"accountId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List posted entries for a PSP account","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/reconciliations":{"post":{"operationId":"createReconciliation","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreatePspReconciliationDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Run Daraja transaction reconciliation","tags":["PSP integrations"]},"get":{"operationId":"listReconciliations","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List PSP reconciliation runs","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/reconciliations/{runId}":{"get":{"operationId":"getReconciliation","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"runId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Get a PSP reconciliation run","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/reconciliations/{runId}/items":{"get":{"operationId":"listReconciliationItems","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"runId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List PSP reconciliation items","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/reconciliations/{runId}/exceptions":{"get":{"operationId":"listReconciliationExceptions","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"runId","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"number"}},{"name":"offset","required":true,"in":"query","schema":{"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"List unresolved PSP reconciliation exceptions","tags":["PSP integrations"]}},"/api/v1/teams/{teamId}/psp/reconciliations/{runId}/items/{itemId}/resolve":{"post":{"operationId":"resolveReconciliationItem","parameters":[{"name":"teamId","required":true,"in":"path","schema":{"type":"string"}},{"name":"runId","required":true,"in":"path","schema":{"type":"string"}},{"name":"itemId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolvePspReconciliationItemDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]},{"bearer":[]}],"summary":"Resolve a PSP reconciliation exception","tags":["PSP integrations"]}},"/api/v1/teams/{id}/billing":{"get":{"description":"Resolves the free-plan default for teams with no stored billing metadata. Readable by members of the team.","operationId":"getTeamBilling","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get a team's billing state","tags":["billing"]}},"/api/v1/teams/{id}/billing/cancel":{"post":{"description":"Access continues to the end of the paid period, then the team resolves as the free plan. Cancelling is not a refund.","operationId":"cancelSubscription","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Cancel a team's subscription","tags":["billing"]}},"/api/v1/teams/{id}/billing/plan":{"put":{"description":"Re-expands plan-derived entitlements. Manual overrides are preserved.","operationId":"setTeamPlan","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetTeamPlanDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Move a team onto a plan","tags":["billing"]}},"/api/v1/teams/{id}/billing/overrides/{entitlementKey}":{"put":{"description":"Overrides win over plan-derived entitlements, so this both grants access a plan does not include and revokes access a plan does.","operationId":"setEntitlementOverride","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"entitlementKey","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetEntitlementOverrideDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Grant or suspend one entitlement for a team","tags":["billing"]},"delete":{"description":"Returns the team to whatever its plan grants. This is not the same as denying the entitlement.","operationId":"clearEntitlementOverride","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"entitlementKey","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Remove an entitlement override","tags":["billing"]}},"/api/v1/teams/{id}/billing/invoices":{"post":{"description":"Creates a Minmo Pay invoice for the plan. The team moves onto the plan when the invoice settles, not when it is raised. Idempotent per team, plan, and period.","operationId":"createSubscriptionInvoice","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscriptionInvoiceDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Raise a subscription invoice for a team","tags":["billing"]}},"/api/v1/teams/{id}/billing/grants":{"post":{"description":"Creates a tracked Minmo Pay invoice, marks it settled in BTCPay as an administrative grant, and applies the authoritative settled invoice through normal billing settlement.","operationId":"grantTeamSubscription","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSubscriptionInvoiceDto"}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Grant a paid subscription tier to a team","tags":["billing"]}},"/api/v1":{"get":{"description":"Get general information about the Minmo API service.\n\n    **Information Provided:**\n    - API name and description\n    - Current version\n    - Environment (production/staging/development)\n    - Build information\n    - Deployment timestamp\n    - Service uptime\n\n    **API Features:**\n    - RESTful design\n    - JWT authentication\n    - Role-based access control\n    - Real-time webhooks\n    - Comprehensive logging\n\n    **Available Modules:**\n    - Authentication & Users\n    - Agent Management\n    - Swap Operations\n    - Bitcoin/Lightning Integration\n    - Liquidity Management\n    - FX Rate Services\n\n    **Documentation:**\n    - OpenAPI/Swagger at /api-docs\n    - Detailed endpoint descriptions\n    - Request/response examples\n    - Authentication guide","operationId":"getInfo","parameters":[],"responses":{"200":{"description":"API information retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"Minmo API"},"description":{"type":"string","example":"P2P Bitcoin exchange platform API"},"version":{"type":"string","example":"2.0.0"},"environment":{"type":"string","example":"production"},"buildNumber":{"type":"string","example":"build-2024.1.15-1234"},"deployedAt":{"type":"string","format":"date-time"},"uptime":{"type":"number","example":3600000,"description":"Uptime in milliseconds"},"documentation":{"type":"string","example":"/api-docs"},"support":{"type":"string","example":"support@minmo.io"}}}}}}},"summary":"API information","tags":["health"]}},"/api/v1/health":{"get":{"description":"Check the overall health status of the API service.\n\n    **Health Checks:**\n    - API service status\n    - Database connectivity\n    - Redis cache availability\n    - Lightning node connection\n    - External service dependencies\n\n    **Response Codes:**\n    - 200: All systems operational\n    - 503: Service degraded or unavailable\n\n    **Monitoring Integration:**\n    - Used by load balancers\n    - Kubernetes liveness probe\n    - Uptime monitoring services\n    - Alert systems\n\n    **Check Frequency:**\n    - Load balancer: Every 10 seconds\n    - Monitoring: Every 30 seconds\n    - Kubernetes: Every 60 seconds\n\n    **Dependencies Checked:**\n    - PostgreSQL database\n    - Redis cache\n    - Hexclave authentication\n    - Lightning providers\n    - FX rate sources","operationId":"getHealth","parameters":[],"responses":{"200":{"description":"Service is healthy - All systems operational","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"healthy","enum":["healthy","degraded","unhealthy"]},"timestamp":{"type":"string","format":"date-time"},"uptime":{"type":"number","example":3600000,"description":"Service uptime in milliseconds"},"checks":{"type":"object","properties":{"database":{"type":"string","enum":["healthy","unhealthy"],"example":"healthy"},"cache":{"type":"string","enum":["healthy","unhealthy"],"example":"healthy"},"authentication":{"type":"string","enum":["healthy","unhealthy"],"example":"healthy"},"lightning":{"type":"string","enum":["healthy","unhealthy"],"example":"healthy"},"fxRates":{"type":"string","enum":["healthy","unhealthy"],"example":"healthy"}}},"version":{"type":"string","example":"2.0.0"}}}}}},"503":{"description":"Service unavailable - One or more critical components are down","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"unhealthy"},"message":{"type":"string","example":"Database connection failed"},"failedChecks":{"type":"array","items":{"type":"string"},"example":["database"]}}}}}}},"summary":"Health check endpoint","tags":["health"]}},"/api/v1/users/search":{"get":{"description":"\n      Search local Mini users by various criteria with pagination support.\n      This is an administrative product-data lookup, not a provider-auth endpoint.\n\n      **Search Parameters (all optional):**\n      - userId: Exact UUID match\n      - email: Case-insensitive partial match\n      - wrapperSubject: Exact match on the wrapper identity subject stored in external_id\n      - status: Exact match on user status (pending, active, suspended)\n      - role: Direct Minmo user role\n      - teamId: Exact Hexclave team membership\n      - authType: Authentication type (hexclave, nostr)\n\n      **Pagination:**\n      - page: Page number (starts from 1)\n      - limit: Items per page (max 100)\n      - sortBy: Sort field (createdAt, updatedAt, email, id)\n      - sortOrder: Sort direction (ASC, DESC)\n    ","operationId":"searchUsers","parameters":[{"name":"userId","required":false,"in":"query","description":"User ID (UUID)","schema":{"example":"123e4567-e89b-12d3-a456-426614174000","type":"string"}},{"name":"email","required":false,"in":"query","description":"Email address (partial match, case-insensitive)","schema":{"example":"john@example.com","type":"string"}},{"name":"wrapperSubject","required":false,"in":"query","description":"External identity ID","schema":{"example":"hexclave:123e4567-e89b-12d3-a456-426614174000","type":"string"}},{"name":"status","required":false,"in":"query","description":"User status","schema":{"enum":["pending","active","suspended"],"type":"string"}},{"name":"role","required":false,"in":"query","description":"Direct Minmo user role","schema":{"enum":["minmo_admin","minmo_partner","minmo_agent"],"type":"string"}},{"name":"teamId","required":false,"in":"query","description":"Hexclave team ID","schema":{"example":"team_123","type":"string"}},{"name":"authType","required":false,"in":"query","description":"Authentication type","schema":{"enum":["hexclave","nostr"],"type":"string"}},{"name":"page","required":false,"in":"query","description":"Page number (starts from 1)","schema":{"minimum":1,"default":1,"example":1,"type":"number"}},{"name":"limit","required":false,"in":"query","description":"Number of items per page (max 100)","schema":{"minimum":1,"maximum":100,"default":20,"example":20,"type":"number"}},{"name":"sortBy","required":false,"in":"query","description":"Sort by field","schema":{"enum":["createdAt","updatedAt","email","id"],"type":"string"}},{"name":"sortOrder","required":false,"in":"query","description":"Sort order","schema":{"enum":["ASC","DESC"],"type":"string"}}],"responses":{"200":{"description":"Users found successfully"},"400":{"description":"Invalid search parameters"},"401":{"description":"Authentication required"},"500":{"description":"Internal server error"}},"security":[{"bearer":[]}],"summary":"Search local Mini users","tags":["users"]}},"/api/v1/users/preferences":{"get":{"operationId":"getPreferences","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NotificationPreferenceResponse"}}}}}},"security":[{"bearer":[]}],"summary":"Get the authenticated user's event preferences","tags":["users"]}},"/api/v1/users/preferences/{type}":{"get":{"operationId":"getPreference","parameters":[{"name":"type","required":true,"in":"path","schema":{"enum":["otc.swap.created","otc.swap.escrow.pending","otc.swap.escrow.locked","otc.swap.claimed","otc.swap.payment.instructed","otc.swap.payment.pending","otc.swap.payment.submitted","otc.swap.payment.confirmed.user","otc.swap.payment.confirmed.agent","otc.swap.confirmation.pending","otc.swap.completed","otc.swap.cancelled","otc.swap.refund.initiated","otc.swap.refund.failed","otc.swap.disputed","otc.swap.dispute.evidence.collection","otc.swap.dispute.internal.review","otc.swap.dispute.review","otc.swap.dispute.resolved","otc.swap.refunded","otc.swap.expired","otc.swap.fiat.sender.timeout","otc.swap.fiat.receiver.timeout","otc.swap.transferred.to.backup","otc.agent.registered","otc.agent.updated","otc.agent.availability.changed","otc.agent.team.associated","otc.agent.team.removed","otc.rate.quoted","otc.rate.updated","otc.rate.expired","pay.invoice.created","pay.invoice.processing","pay.invoice.settled","pay.invoice.expired","pay.invoice.invalid","pay.store.connected","pay.store.connection.failed","wallet.synced","wallet.deposits.discovered","wallet.deposits.unclaimed","wallet.deposits.claimed","wallet.payment.pending","wallet.payment.succeeded","wallet.payment.failed","escrow.reference.issued","escrow.funding.confirmed","escrow.dispute.resolution.recorded","escrow.released","escrow.refunded","escrow.expired","psp.connection.created","psp.connection.activated","psp.connection.suspended","psp.connection.revoked","psp.payment.created","psp.payment.submitted","psp.payment.pending","psp.payment.succeeded","psp.payment.failed","psp.payment.outcome.unknown","psp.payment.cancelled","psp.reconciliation.completed","psp.reconciliation.exception.detected","psp.reconciliation.exception.resolved"],"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get one authenticated user event preference","tags":["users"]},"patch":{"operationId":"updatePreference","parameters":[{"name":"type","required":true,"in":"path","schema":{"enum":["otc.swap.created","otc.swap.escrow.pending","otc.swap.escrow.locked","otc.swap.claimed","otc.swap.payment.instructed","otc.swap.payment.pending","otc.swap.payment.submitted","otc.swap.payment.confirmed.user","otc.swap.payment.confirmed.agent","otc.swap.confirmation.pending","otc.swap.completed","otc.swap.cancelled","otc.swap.refund.initiated","otc.swap.refund.failed","otc.swap.disputed","otc.swap.dispute.evidence.collection","otc.swap.dispute.internal.review","otc.swap.dispute.review","otc.swap.dispute.resolved","otc.swap.refunded","otc.swap.expired","otc.swap.fiat.sender.timeout","otc.swap.fiat.receiver.timeout","otc.swap.transferred.to.backup","otc.agent.registered","otc.agent.updated","otc.agent.availability.changed","otc.agent.team.associated","otc.agent.team.removed","otc.rate.quoted","otc.rate.updated","otc.rate.expired","pay.invoice.created","pay.invoice.processing","pay.invoice.settled","pay.invoice.expired","pay.invoice.invalid","pay.store.connected","pay.store.connection.failed","wallet.synced","wallet.deposits.discovered","wallet.deposits.unclaimed","wallet.deposits.claimed","wallet.payment.pending","wallet.payment.succeeded","wallet.payment.failed","escrow.reference.issued","escrow.funding.confirmed","escrow.dispute.resolution.recorded","escrow.released","escrow.refunded","escrow.expired","psp.connection.created","psp.connection.activated","psp.connection.suspended","psp.connection.revoked","psp.payment.created","psp.payment.submitted","psp.payment.pending","psp.payment.succeeded","psp.payment.failed","psp.payment.outcome.unknown","psp.payment.cancelled","psp.reconciliation.completed","psp.reconciliation.exception.detected","psp.reconciliation.exception.resolved"],"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePreferenceDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update one authenticated user event preference","tags":["users"]}},"/api/v1/users/preferences/bulk-update":{"post":{"operationId":"bulkUpdatePreferences","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"}}}}},"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Bulk update authenticated user event preferences","tags":["users"]}},"/api/v1/users/preferences/reset":{"post":{"operationId":"resetPreferences","parameters":[],"responses":{"201":{"description":""}},"security":[{"bearer":[]}],"summary":"Reset authenticated user event preferences","tags":["users"]}},"/api/v1/users/preferences/{type}/effective":{"get":{"operationId":"getEffectivePreference","parameters":[{"name":"type","required":true,"in":"path","schema":{"enum":["otc.swap.created","otc.swap.escrow.pending","otc.swap.escrow.locked","otc.swap.claimed","otc.swap.payment.instructed","otc.swap.payment.pending","otc.swap.payment.submitted","otc.swap.payment.confirmed.user","otc.swap.payment.confirmed.agent","otc.swap.confirmation.pending","otc.swap.completed","otc.swap.cancelled","otc.swap.refund.initiated","otc.swap.refund.failed","otc.swap.disputed","otc.swap.dispute.evidence.collection","otc.swap.dispute.internal.review","otc.swap.dispute.review","otc.swap.dispute.resolved","otc.swap.refunded","otc.swap.expired","otc.swap.fiat.sender.timeout","otc.swap.fiat.receiver.timeout","otc.swap.transferred.to.backup","otc.agent.registered","otc.agent.updated","otc.agent.availability.changed","otc.agent.team.associated","otc.agent.team.removed","otc.rate.quoted","otc.rate.updated","otc.rate.expired","pay.invoice.created","pay.invoice.processing","pay.invoice.settled","pay.invoice.expired","pay.invoice.invalid","pay.store.connected","pay.store.connection.failed","wallet.synced","wallet.deposits.discovered","wallet.deposits.unclaimed","wallet.deposits.claimed","wallet.payment.pending","wallet.payment.succeeded","wallet.payment.failed","escrow.reference.issued","escrow.funding.confirmed","escrow.dispute.resolution.recorded","escrow.released","escrow.refunded","escrow.expired","psp.connection.created","psp.connection.activated","psp.connection.suspended","psp.connection.revoked","psp.payment.created","psp.payment.submitted","psp.payment.pending","psp.payment.succeeded","psp.payment.failed","psp.payment.outcome.unknown","psp.payment.cancelled","psp.reconciliation.completed","psp.reconciliation.exception.detected","psp.reconciliation.exception.resolved"],"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get effective event preference for the user","tags":["users"]}},"/api/v1/users/{id}":{"get":{"operationId":"getUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Get local Mini user detail","tags":["users"]},"patch":{"operationId":"updateUserProfile","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserProfileDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Update local Mini user profile fields","tags":["users"]},"delete":{"description":"\n      Permanently delete a local Mini user. When the local user is linked to\n      Hexclave, the linked Hexclave server user is deleted before removing the\n      local record.\n    ","operationId":"deleteUser","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"User deleted successfully"},"403":{"description":"Cannot delete the currently authenticated user"},"404":{"description":"User not found"}},"security":[{"bearer":[]}],"summary":"Delete a local Mini user and linked Hexclave user","tags":["users"]}},"/api/v1/users/{id}/nostr-identity/private-key":{"post":{"description":"Returns the selected user's Nostr private key in nsec backup form when the identity is operator-custodied. Every reveal attempt is persisted in the Nostr identity export audit trail.","operationId":"revealUserNostrPrivateKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"Nostr private key export returned"},"400":{"description":"Private key is not exportable"},"404":{"description":"User not found"}},"security":[{"bearer":[]}],"summary":"Reveal a user's managed Nostr private key","tags":["users"]}},"/api/v1/users/bulk/roles":{"patch":{"description":"Replaces direct Minmo roles for selected local users. Team roles remain managed through team membership endpoints.","operationId":"bulkUpdateUserRoles","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUpdateUserRolesDto"}}}},"responses":{"200":{"description":""}},"security":[{"bearer":[]}],"summary":"Assign direct Minmo roles to selected users","tags":["users"]}},"/api/v1/users/{id}/roles":{"patch":{"description":"\n      Assign direct user roles for a local Mini user and write those roles\n      through to Hexclave project permissions when the user has a linked\n      Hexclave identity. Team roles are intentionally excluded because they are\n      scoped to a specific team and should be administered through team\n      membership endpoints.\n    ","operationId":"updateUserRoles","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUserRolesDto"}}}},"responses":{"200":{"description":"User roles updated successfully"},"403":{"description":"Insufficient permissions"},"404":{"description":"User not found"}},"security":[{"bearer":[]}],"summary":"Assign direct Minmo user roles","tags":["users"]}}},"info":{"title":"MINMO API Documentation","description":"Comprehensive API documentation for MINMO service","version":"1.0","contact":{}},"tags":[{"name":"Accounting & Reporting","description":"Accounting & Reporting operations"},{"name":"agent-activity","description":"Scoped agent activity dashboards across agents, swaps, and metrics"},{"name":"agent-discovery","description":"Public agent discovery for swap matching and selection"},{"name":"agents","description":"Agent management operations"},{"name":"Analytics","description":"Analytics operations"},{"name":"auth","description":"Authentication and authorization operations including hosted auth handoff, Nostr auth, provisioning, and session handling"},{"name":"billing","description":"billing operations"},{"name":"documentation","description":"documentation operations"},{"name":"Escrow","description":"Escrow operations"},{"name":"Events","description":"Events operations"},{"name":"fx","description":"Foreign exchange (FX) rate operations for real-time currency conversion and rate management"},{"name":"health","description":"System health monitoring and API information endpoints"},{"name":"liquidity","description":"liquidity operations"},{"name":"Overview","description":"Overview operations"},{"name":"Pay","description":"Pay operations"},{"name":"PSP integrations","description":"PSP integrations operations"},{"name":"referral","description":"Referral code management and verification"},{"name":"swap","description":"Cryptocurrency swap operations"},{"name":"system referral codes","description":"system referral codes operations"},{"name":"team-agents","description":"Team-scoped agent association operations"},{"name":"team-fx","description":"Team-scoped FX rate source configuration and rate operations"},{"name":"teams","description":"teams operations"},{"name":"users","description":"Administrative local Mini user lookup and profile operations"},{"name":"Wallet","description":"Wallet operations"}],"servers":[],"components":{"securitySchemes":{"bearerAuth":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"access token authentication"}},"schemas":{"CreateAuthHandoffDto":{"type":"object","properties":{"clientId":{"type":"string","description":"Registered origin app identifier","enum":["console","mobile","ops"],"example":"console"},"redirectUri":{"type":"string","description":"Exact callback URI owned by the origin app","example":"http://localhost:3000/auth/callback"},"codeChallenge":{"type":"string","description":"PKCE code challenge","example":"Z0FBQUFBQm..."},"codeChallengeMethod":{"type":"string","description":"PKCE challenge method","example":"S256","default":"S256"},"hexclaveRefreshToken":{"type":"object","description":"Hexclave refresh token from the centralized auth app"}},"required":["clientId","redirectUri","codeChallenge"]},"ExchangeAuthHandoffDto":{"type":"object","properties":{"clientId":{"type":"string","description":"Registered origin app identifier","enum":["console","mobile","ops"],"example":"console"},"redirectUri":{"type":"string","description":"Exact callback URI used when creating the code","example":"http://localhost:3000/auth/callback"},"code":{"type":"string","description":"Short-lived handoff code returned by auth app"},"codeVerifier":{"type":"string","description":"PKCE code verifier generated by the origin app"}},"required":["clientId","redirectUri","code","codeVerifier"]},"RegisterAgentDto":{"type":"object","properties":{"userId":{"type":"string","description":"User ID to create agent for (admin only). If not provided, uses the authenticated user's ID","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"referralCode":{"type":"string","description":"Optional referral code. Team-scoped codes activate the agent's team association; agents may also enter one after signup before swap links are shown.","example":"MINMO2025"},"currencyChannels":{"type":"object","description":"Currency-centric payment config. When provided, supportedCurrencies/supportedChannels/paymentDetails are derived.","example":{"KES":{"channels":["mpesa_phone","mpesa_till"],"details":{"mpesa_phone":{"phoneNumber":"+254712345678"},"mpesa_till":{"tillNumber":"123456"}}}}},"supportedCurrencies":{"type":"array","description":"List of currencies the agent supports (required when currencyChannels not provided)","example":["USD","KES"],"minItems":1,"items":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"]}},"supportedChannels":{"type":"array","description":"Payment channels the agent can use (required when currencyChannels not provided)","example":["bank_transfer","mpesa_phone"],"minItems":1,"items":{"type":"string","enum":["mpesa_phone","mpesa_till","mpesa_paybill","airtel_money","airtel_money_till","tnm_mpamba","tnm_mpamba_merchant","bank_transfer","card","cash","lightning","onchain"]}},"minTransactionAmount":{"type":"string","description":"Minimum transaction amount in satoshis","example":"100000","pattern":"^[0-9]+$"},"maxTransactionAmount":{"type":"string","description":"Maximum transaction amount in satoshis","example":"10000000","pattern":"^[0-9]+$"},"dailyVolumeLimit":{"type":"string","description":"Daily volume limit in satoshis","example":"100000000","pattern":"^[0-9]+$"},"onrampMarginBp":{"type":"number","description":"Onramp margin in basis points (100 basis points = 1%). Applied when users buy Bitcoin","example":250,"minimum":0,"maximum":10000},"offrampMarginBp":{"type":"number","description":"Offramp margin in basis points (100 basis points = 1%). Applied when users sell Bitcoin","example":300,"minimum":0,"maximum":10000},"operatingHours":{"type":"object","description":"Operating hours configuration for the agent","example":{"monday":{"start":"09:00","end":"17:00"},"tuesday":{"start":"09:00","end":"17:00"},"timezone":"UTC"}},"settings":{"type":"object","description":"Additional agent settings and preferences","example":{"autoAccept":true,"notificationPreferences":{"email":true,"sse":true},"maxConcurrentSwaps":10,"publiclyVisible":false,"lightningAddress":"agent@example.com","walletPreference":"external"}},"paymentDetails":{"type":"object","description":"Payment details keyed by channel (required when currencyChannels not provided)","example":{"mpesa_phone":{"phoneNumber":"+254712345678"},"bank_transfer":{"accountName":"John Doe","accountNumber":"1234567890","bankName":"Equity Bank","transferPurpose":"Business payment"}}}},"required":["supportedCurrencies","supportedChannels","minTransactionAmount","maxTransactionAmount","dailyVolumeLimit","onrampMarginBp","offrampMarginBp"]},"HexclaveProvisionDto":{"type":"object","properties":{"firstName":{"type":"string","description":"User first name to store in the local Minmo profile after Hexclave signup","example":"Test"},"lastName":{"type":"string","description":"User last name to store in the local Minmo profile after Hexclave signup","example":"User"},"email":{"type":"string","description":"Email address used during Hexclave signup. Must match the verified Hexclave token email when the token includes one.","example":"example@minmo.to"},"referralCode":{"type":"string","description":"Referral code used during Hexclave signup. May be a regular referral code or the one-time bootstrap admin code.","example":"MMAB1C2D"},"invitationCode":{"type":"string","description":"Hexclave team invitation code used as onboarding authority instead of a referral code"},"userRole":{"type":"string","description":"Local Mini role to assign during Hexclave provisioning. Console passes minmo_partner; mobile passes minmo_agent.","enum":["minmo_agent","minmo_partner"],"example":"minmo_partner","default":"minmo_agent"},"agentConfig":{"description":"Optional agent configuration to create agent profile during Hexclave registration","allOf":[{"$ref":"#/components/schemas/RegisterAgentDto"}]}},"required":["firstName","lastName","email"]},"NostrVerifyDto":{"type":"object","properties":{"challenge":{"type":"string","description":"Challenge string from POST /auth/nostr/challenge","example":"minmo:login:abc123:1234567890"},"pubkey":{"type":"string","description":"NOSTR public key (hex or npub). Required if signature is used; omit when using event."},"signature":{"type":"string","description":"Schnorr signature of sha256(challenge) in hex. Required if pubkey is used; omit when using event."},"event":{"type":"object","description":"Signed NOSTR event with content = challenge (e.g. kind 27235). Alternative to pubkey+signature for NIP-07."},"loginOnly":{"type":"boolean","description":"If true, only existing NOSTR users are allowed to sign in. When no user exists for the provided pubkey, the API returns a nostr_user_not_found response instead of auto-creating a new user.","default":false}},"required":["challenge"]},"NostrRegisterDto":{"type":"object","properties":{"challenge":{"type":"string","description":"Challenge string from POST /auth/nostr/challenge","example":"minmo:login:abc123:1234567890"},"event":{"type":"object","description":"Signed NOSTR event with content = challenge (e.g. kind 27235). Used to prove ownership of the NOSTR key during registration."},"firstName":{"type":"string","description":"User first name","example":"NOSTR"},"lastName":{"type":"string","description":"User last name","example":"abcd1234"},"email":{"type":"string","description":"User email address","example":"nostr-user@example.com"},"agentConfig":{"description":"Optional agent configuration to create agent profile during NOSTR registration. Includes referralCode and currency/channel settings.","allOf":[{"$ref":"#/components/schemas/RegisterAgentDto"}]}},"required":["challenge","event","firstName","lastName","email"]},"RefreshTokenDto":{"type":"object","properties":{"refresh_token":{"type":"string","description":"Refresh token obtained from a Minmo hosted auth or Nostr session","example":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}},"required":["refresh_token"]},"PatchMeDto":{"type":"object","properties":{"email":{"type":"object","description":"User email address","example":"user@example.com"},"firstName":{"type":"string","description":"First name","example":"John"},"lastName":{"type":"string","description":"Last name","example":"Doe"}}},"UpdateTeamReferralCodeDto":{"type":"object","properties":{"allowedUses":{"type":"array","description":"Signup flows allowed to use the active partner referral code","example":["agent_invite"],"items":{"type":"string","enum":["agent_invite","partner_member_signup"]}}},"required":["allowedUses"]},"RotateTeamReferralCodeDto":{"type":"object","properties":{"allowedUses":{"type":"array","description":"Signup flows allowed to use the replacement code. When omitted, the current policy is preserved.","items":{"type":"string","enum":["agent_invite","partner_member_signup"]}}}},"AcceptTeamInvitationDto":{"type":"object","properties":{"code":{"type":"string","description":"Invitation code Hexclave appended to the console callback URL"}},"required":["code"]},"CreateTeamDto":{"type":"object","properties":{"displayName":{"type":"string","description":"Team display name","example":"Minmo Kenya"}},"required":["displayName"]},"UpdateTeamDto":{"type":"object","properties":{"displayName":{"type":"string","description":"Team display name"}}},"UpdateTeamCurrencySettingsDto":{"type":"object","properties":{"supported_currencies":{"type":"array","description":"Fiat currencies this team supports","example":["KES","MWK"],"items":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"]}},"display_currency":{"type":"string","description":"Default display currency for this team","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"example":"KES"}},"required":["supported_currencies","display_currency"]},"UpdateEscrowFeePolicyDto":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether the team escrow fee is enabled"},"onrampBps":{"type":"number","description":"Onramp escrow fee in basis points","minimum":0,"maximum":10000},"offrampBps":{"type":"number","description":"Offramp escrow fee in basis points","minimum":0,"maximum":10000},"minimumSats":{"type":"string","description":"Optional minimum fee in sats"},"maximumSats":{"type":"string","description":"Optional maximum fee in sats"}}},"UpdateFeatureDto":{"type":"object","properties":{"state":{"type":"string","description":"Resolved feature availability state","enum":["unavailable","available","enabled","configured","active","suspended"]},"label":{"type":"string","description":"Feature display label"},"description":{"type":"string","description":"Feature display description"},"capabilities":{"type":"object","description":"Nested feature capability metadata"},"config":{"type":"object","description":"Non-secret feature configuration metadata"}}},"AddTeamMemberDto":{"type":"object","properties":{"userId":{"type":"string","description":"Local Minmo user ID to add to the team"}},"required":["userId"]},"InviteTeamMemberDto":{"type":"object","properties":{"email":{"type":"string","description":"Email address to invite to the team"},"callbackUrl":{"type":"string","description":"Absolute HTTP(S) URL Hexclave should send invitees to after accepting the invitation","example":"https://console.minmo.to/team-invitations/accept"}},"required":["email","callbackUrl"]},"UpdateTeamMemberRolesDto":{"type":"object","properties":{"roles":{"type":"array","description":"Team roles to grant to this member in the team scope","example":["team_member"],"items":{"type":"string","enum":["team_admin","team_member"]}}},"required":["roles"]},"CreateTeamApiKeyDto":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable API key description","example":"Production settlement service"},"expiresAt":{"type":"string","description":"Optional ISO timestamp when the key expires"},"isPublic":{"type":"boolean","description":"Whether Hexclave should treat this key as public","default":false}},"required":["description"]},"ApiKeyPolicyResourcesDto":{"type":"object","properties":{"teamIds":{"description":"Explicit team IDs this key may access","type":"array","items":{"type":"string"}},"agentIds":{"description":"Explicit agent IDs this key may access","type":"array","items":{"type":"string"}}}},"UpdateTeamApiKeyPolicyDto":{"type":"object","properties":{"resourceScope":{"type":"string","description":"Resource scope granted to this API key","enum":["team","platform","explicit"],"example":"team"},"capabilities":{"type":"array","description":"Reusable permission bundles granted to this API key","example":["swap.readonly"],"items":{"type":"string","enum":["team.readonly","team.read_write","swap.readonly","swap.read_write","escrow.readonly","escrow.operations","escrow.admin","pay.readonly","pay.read_write","psp.readonly","psp.collections","psp.disbursements","psp.admin","wallet.readonly","wallet.read_write","accounting.readonly","accounting.read_write"]}},"permissions":{"type":"array","description":"Advanced Mini permissions granted directly to this API key","example":["agent:read_all"],"items":{"type":"string","enum":["system:config","system:monitor","system:audit","referral_code:create","referral_code:read","user:read","user:write","user:delete","user:manage_roles","agent:register","agent:manage_own","agent:manage_all","agent:read_all","swap:create","swap:read_own","swap:read_all","swap:approve","swap:cancel_own","swap:cancel_all","liquidity:manage_own","liquidity:manage_all","liquidity:read_all","bitcoin:wallet_read","bitcoin:wallet_receive","bitcoin:wallet_send","escrow:create","escrow:read","escrow:verify_funding","escrow:expire","escrow:release","escrow:refund","escrow:resolve_dispute","escrow:descriptor_publish","fx:rates_manage","fx:rates_read","reports:read_own","reports:read_all","reports:export","partner:read_own","partner:manage_own","partner:read_all","partner:manage_all","partner:agent_invite","partner:agent_remove","partner:agent_read","partner:agent_manage","partner:agents_read","partner:swaps_read","partner:swaps_manage","partner:liquidity_read","partner:metrics_read","partner:services_create","partner:services_manage","partner:services_read","partner:services_delete","pay:payment_create","pay:payment_read","pay:payment_cancel","pay:event_subscribe","pay:store_read","pay:store_manage","psp:connection_read","psp:connection_manage","psp:payment_create","psp:disbursement_create","psp:payment_read","psp:account_read","psp:event_subscribe","psp:reconciliation_read","psp:reconciliation_run","psp:reconciliation_resolve","accounting:read","accounting:template_manage","accounting:export"]}},"resources":{"description":"Explicit resources used when resourceScope is explicit","allOf":[{"$ref":"#/components/schemas/ApiKeyPolicyResourcesDto"}]}},"required":["resourceScope","permissions"]},"FxRateResponse":{"type":"object","properties":{"baseCurrency":{"type":"string","description":"Base currency code","example":"BTC"},"targetCurrency":{"type":"string","description":"Target currency code","example":"KES"},"rate":{"type":"number","description":"FX rate","example":7500000},"timestamp":{"type":"string","description":"Rate timestamp","example":"2024-01-01T00:00:00.000Z"},"source":{"type":"string","description":"Data source","example":"aggregated"},"confidence":{"type":"number","description":"Confidence level (0-1)","example":0.95}},"required":["baseCurrency","targetCurrency","rate","timestamp","source"]},"AggregatedFxRateResponse":{"type":"object","properties":{"baseCurrency":{"type":"string","description":"Base currency code","example":"BTC"},"targetCurrency":{"type":"string","description":"Target currency code","example":"KES"},"rate":{"type":"number","description":"FX rate","example":7500000},"timestamp":{"type":"string","description":"Rate timestamp","example":"2024-01-01T00:00:00.000Z"},"source":{"type":"string","description":"Data source","example":"aggregated"},"confidence":{"type":"number","description":"Confidence level (0-1)","example":0.95},"sources":{"type":"array","description":"Individual source rates used in aggregation","items":{"type":"object","properties":{"source":{"type":"string","example":"currency_api"},"rate":{"type":"number","example":7500000},"timestamp":{"type":"string","example":"2024-01-01T00:00:00.000Z"}}}}},"required":["baseCurrency","targetCurrency","rate","timestamp","source","sources"]},"HistoricalFxRateResponse":{"type":"object","properties":{"baseCurrency":{"type":"string","description":"Base currency code","example":"BTC"},"targetCurrency":{"type":"string","description":"Target currency code","example":"KES"},"rate":{"type":"number","description":"FX rate","example":7500000},"timestamp":{"type":"string","description":"Rate timestamp","example":"2024-01-01T00:00:00.000Z"},"source":{"type":"string","description":"Data source","example":"aggregated"},"confidence":{"type":"number","description":"Confidence level (0-1)","example":0.95},"sources":{"type":"array","description":"Individual source rates used in aggregation","items":{"type":"object","properties":{"source":{"type":"string","example":"currency_api"},"rate":{"type":"number","example":7500000},"timestamp":{"type":"string","example":"2024-01-01T00:00:00.000Z"}}}},"mode":{"type":"string","enum":["historical"]},"date":{"type":"string","example":"2025-01-01"},"partnerId":{"type":"string"},"policyVersion":{"type":"number","description":"Current Partner source policy used for this valuation"}},"required":["baseCurrency","targetCurrency","rate","timestamp","source","sources","mode","date"]},"SupportedPairsResponse":{"type":"object","properties":{"pairs":{"type":"array","description":"List of supported currency pairs","items":{"type":"string"},"example":["BTC-KES","BTC-USD","USD-KES"]}},"required":["pairs"]},"SourceHealthStatus":{"type":"object","properties":{"supportedModes":{"type":"array","items":{"type":"string","enum":["live","historical"]}},"allowedModes":{"type":"array","items":{"type":"string","enum":["live","historical"]}},"status":{"type":"string","description":"Source health status","example":"healthy"},"lastUpdate":{"type":"string","description":"Last successful update","example":"2024-01-01T00:00:00.000Z"},"error":{"type":"string","description":"Error message if any","example":"Connection timeout"},"responseTime":{"type":"number","description":"Response time in milliseconds","example":250},"enabled":{"type":"boolean","description":"Whether the source is enabled","example":true},"weight":{"type":"number","description":"Normalized aggregation weight assigned to the source","example":0.7}},"required":["status","lastUpdate","error","responseTime","enabled"]},"HealthStatusResponse":{"type":"object","properties":{"sources":{"type":"object","description":"Detailed health status of each rate source","additionalProperties":{"$ref":"#/components/schemas/SourceHealthStatus"},"example":{"currency_api":{"status":"healthy","lastUpdate":"2024-01-01T00:00:00.000Z","responseTime":250,"enabled":true},"coingecko":{"status":"error","error":"Rate limited","responseTime":1000,"enabled":true}}},"healthy":{"type":"boolean","description":"Overall system health","example":true}},"required":["sources","healthy"]},"CacheMetricsResponse":{"type":"object","properties":{"totalEntries":{"type":"number","description":"Total cache entries","example":150},"fxCacheEntries":{"type":"number","description":"FX rate cache entries","example":45},"staleCacheEntries":{"type":"number","description":"Stale cache entries","example":15},"hitRate":{"type":"number","description":"Cache hit rate","example":0.85},"sizeBytes":{"type":"number","description":"Cache size in bytes","example":1024000}},"required":["totalEntries","fxCacheEntries","staleCacheEntries","hitRate","sizeBytes"]},"UpdatePartnerFxRateSourcesDto":{"type":"object","properties":{"sources":{"type":"object","description":"Provider configuration keyed by FX source provider ID","example":{"currency_api":{"enabled":true,"weight":0.7},"coingecko":{"enabled":true,"weight":0.3},"custom_rates":{"enabled":false,"weight":0}}},"custom_rates":{"type":"object","description":"Team custom FX rates keyed by fiat currency code. Rates are expressed as 1 BTC = fiat.","example":{"rates":{"MWK":{"rate":110016398.97,"expiresAt":"2026-07-28T12:30:00.000Z"}}}}},"required":["sources"]},"SwapListSegment":{"type":"string","enum":["open","history"]},"SwapState":{"type":"string","enum":["created","agent_matched","escrow_pending","escrow_locked","payment_instructed","payment_pending","payment_submitted","payment_confirmed_user","payment_confirmed_agent","confirmation_pending","completed","cancelled","refund_initiated","refund_failed","disputed","dispute_evidence_collection","dispute_internal_review","dispute_resolved","dispute_review","refunded","expired","fiat_sender_timeout","fiat_receiver_timeout","transferred_to_backup"]},"SwapType":{"type":"string","enum":["onramp","offramp"]},"Currency":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"]},"DisputeResolution":{"type":"string","enum":["release_to_user","release_to_agent","partial_settlement","full_refund"],"description":"Resolution type for the dispute"},"ResolveDisputeDto":{"type":"object","properties":{"resolution":{"description":"Resolution type for the dispute","example":"release_to_user","allOf":[{"$ref":"#/components/schemas/DisputeResolution"}]},"partialPercentage":{"type":"number","description":"Percentage for partial settlement (0-100). Only applicable when resolution is PARTIAL_SETTLEMENT","example":50,"minimum":0,"maximum":100},"reason":{"type":"string","description":"Detailed reason for the resolution decision","example":"After reviewing the evidence, payment confirmation was verified from the user's bank","minLength":20,"maxLength":2000},"reviewTeamId":{"type":"string","description":"Review team member or arbitrator ID who resolved the dispute","example":"ADMIN-001","pattern":"^[A-Z0-9-]+$"}},"required":["resolution","reason"]},"CancelSwapDto":{"type":"object","properties":{"beneficiaryId":{"type":"string","description":"Beneficiary Nostr public key for authorization.","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","pattern":"^[0-9a-fA-F]{64}$"}}},"RepairSwapDto":{"type":"object","properties":{"action":{"type":"string","enum":["attach_escrow","close_legacy","recover_payout"]},"expectedState":{"type":"string","enum":["created","agent_matched","escrow_pending","escrow_locked","payment_instructed","payment_pending","payment_submitted","payment_confirmed_user","payment_confirmed_agent","confirmation_pending","completed","cancelled","refund_initiated","refund_failed","disputed","dispute_evidence_collection","dispute_internal_review","dispute_resolved","dispute_review","refunded","expired","fiat_sender_timeout","fiat_receiver_timeout","transferred_to_backup"]},"reason":{"type":"string","description":"Reason recorded in the swap repair audit metadata","minLength":1},"newInvoice":{"type":"string","description":"Replacement Lightning payout invoice"},"newOnchainAddress":{"type":"string","description":"Replacement Bitcoin payout address"}},"required":["action","expectedState","reason"]},"ReconcileSwapBody":{"type":"object","properties":{}},"PaymentChannel":{"type":"string","enum":["mpesa_phone","mpesa_till","mpesa_paybill","airtel_money","airtel_money_till","tnm_mpamba","tnm_mpamba_merchant","bank_transfer","card","cash","lightning","onchain"],"description":"Payment channel used for the swap"},"SwapAgentInfo":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the agent","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"type":{"type":"string","description":"Type of agent","example":"human","enum":["human"]},"isAutomated":{"type":"boolean","description":"Whether the agent is automated","example":false},"rating":{"type":"number","description":"Agent's average rating (1.0 to 5.0)","example":4.5,"minimum":1,"maximum":5}},"required":["id","type"]},"SwapConfirmations":{"type":"object","properties":{"user":{"type":"boolean","description":"Whether the user has confirmed the payment","example":true},"agent":{"type":"boolean","description":"Whether the agent has confirmed the payment","example":false}},"required":["user","agent"]},"SwapResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the swap","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"reference":{"type":"string","description":"Human-readable reference for the swap","example":"SWAP-2024-001234"},"beneficiaryId":{"type":"string","description":"Nostr public key of the swap beneficiary","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"},"type":{"description":"Type of swap operation","example":"onramp","allOf":[{"$ref":"#/components/schemas/SwapType"}]},"state":{"description":"Current state of the swap in the workflow","example":"agent_matched","allOf":[{"$ref":"#/components/schemas/SwapState"}]},"fiatAmount":{"type":"string","description":"Fiat amount in smallest units (e.g., cents)","example":"10000"},"fiatCurrency":{"description":"Fiat currency code (ISO 4217)","example":"USD","allOf":[{"$ref":"#/components/schemas/Currency"}]},"bitcoinAmount":{"type":"string","description":"Bitcoin amount in satoshis","example":"500000"},"exchangeRate":{"type":"string","description":"Exchange rate applied to the swap","example":"45000.50"},"agentMargin":{"type":"number","description":"Agent margin in basis points","example":250},"fees":{"type":"object","description":"Immutable fee history captured for the swap"},"paymentChannel":{"description":"Payment channel used for the swap","example":"bank_transfer","allOf":[{"$ref":"#/components/schemas/PaymentChannel"}]},"userPaymentDetails":{"type":"object","description":"User payment details including Bitcoin destination or fiat payment information","example":{"lightningInvoice":"lnbc1000n1ps9qx3pp5..."}},"agentPaymentDetails":{"type":"object","description":"Agent payment details from agent settings. Only visible to authorized parties.","example":{"phoneNumber":"254712345678","accountNumber":"1234567890","bankName":"Example Bank"}},"paymentInstructions":{"type":"object","description":"Payment instructions generated for the current swap state"},"agent":{"description":"Agent information if matched","allOf":[{"$ref":"#/components/schemas/SwapAgentInfo"}]},"agentId":{"type":"string","description":"Assigned agent identifier, when an agent has been selected","format":"uuid"},"agentTeamContext":{"type":"object","description":"Snapshot of the agent's active primary team association captured when the agent was selected, claimed, or transferred.","example":{"primaryTeamId":"5acff16a-7c53-47e0-8558-54481d6d7b3f","agentId":"550e8400-e29b-41d4-a716-446655440000","capturedAt":"2026-07-22T09:00:00.000Z","source":"claim"}},"escrowInvoice":{"type":"string","description":"Lightning invoice for escrow (visible during escrow states)","example":"lnbc1000n1ps9qx3pp5..."},"confirmations":{"description":"Payment confirmation status from both parties","allOf":[{"$ref":"#/components/schemas/SwapConfirmations"}]},"canCancel":{"type":"boolean","description":"Indicates whether the swap can be cancelled in its current state","example":true},"createdAt":{"type":"string","description":"ISO 8601 timestamp when the swap was created","example":"2024-01-15T10:30:00.000Z","format":"date-time"},"updatedAt":{"type":"string","description":"ISO 8601 timestamp when the swap was last updated","format":"date-time"},"claimedAt":{"type":"string","description":"ISO 8601 timestamp when an agent claimed the swap","example":"2024-01-15T10:35:00.000Z","format":"date-time"},"completedAt":{"type":"string","description":"ISO 8601 timestamp when the swap was completed","example":"2024-01-15T11:00:00.000Z","format":"date-time"},"disputedAt":{"type":"string","description":"ISO 8601 timestamp when the swap entered dispute","format":"date-time"},"resolvedAt":{"type":"string","description":"ISO 8601 timestamp when the dispute was resolved","format":"date-time"},"metadata":{"type":"object","description":"Additional metadata including dispute details and payment proofs","example":{"disputeDetails":null,"paymentProofUser":null,"paymentProofAgent":null,"agentSelectionMode":"direct"}}},"required":["id","reference","beneficiaryId","type","state","fiatAmount","fiatCurrency","bitcoinAmount","exchangeRate","agentMargin","fees","paymentChannel","confirmations","createdAt","updatedAt"]},"PaginatedSwapsResponse":{"type":"object","properties":{"data":{"description":"Array of swap records","type":"array","items":{"$ref":"#/components/schemas/SwapResponse"}},"total":{"type":"number","description":"Total number of swaps matching the query","example":150},"page":{"type":"number","description":"Current page number","example":1},"limit":{"type":"number","description":"Number of items per page","example":10},"totalPages":{"type":"number","description":"Total number of pages available","example":15}},"required":["data","total","page","limit","totalPages"]},"AgentSelectionMode":{"type":"string","enum":["direct","auto"],"description":"Agent selection mode. Automatically determined based on agentId presence"},"CreateSwapDto":{"type":"object","properties":{"quoteId":{"type":"string","description":"Partner-scoped quote identifier used for this swap"},"rateSnapshot":{"type":"object","description":"The quote snapshot returned by the OTC quote endpoint"},"type":{"description":"Type of swap operation","example":"onramp","allOf":[{"$ref":"#/components/schemas/SwapType"}]},"fiatAmount":{"type":"string","description":"Fiat amount in smallest units (e.g., cents for USD). Required for fiat-led mode: onramp with onChainAddress, and all offramps. Must be omitted when lightningInvoice is provided (invoice-led mode). Exactly one of fiatAmount or lightningInvoice must be the amount source.","example":"10000","pattern":"^[0-9]+$"},"fiatCurrency":{"description":"Fiat currency code following ISO 4217 standard","example":"USD","allOf":[{"$ref":"#/components/schemas/Currency"}]},"paymentChannel":{"description":"Payment channel/method for the swap","example":"bank_transfer","allOf":[{"$ref":"#/components/schemas/PaymentChannel"}]},"agentMargin":{"type":"number","description":"Agent margin in basis points (100 basis points = 1%)","example":250,"minimum":0,"maximum":10000},"reference":{"type":"string","description":"Unique reference identifier for the swap","example":"SWAP-2024-001234","pattern":"^[A-Z0-9-]+$"},"userPaymentDetails":{"type":"object","description":"User payment details: onChainAddress (use with fiatAmount) or lightningInvoice (amount from invoice; do not send fiatAmount). For offramp, do not send lightningInvoice.","example":{"onChainAddress":"bcrt1qxqqwhnsj5tyqzasrrmq7nry0q53m0kyva65ssc","bitcoinAmountSats":"500000"}},"agentPaymentDetails":{"type":"object","description":"Agent payment details populated from agent settings. Contains payment information for where the agent receives or sends payments.","example":{"phoneNumber":"254712345678","accountNumber":"1234567890","bankName":"Example Bank"}},"metadata":{"type":"object","description":"Additional metadata for the swap","example":{"userNote":"Urgent transfer","source":"mobile_app","ipAddress":"192.168.1.1"}},"agentId":{"type":"string","description":"Pre-selected agent ID for direct selection. The swap is saved with the agent context and remains claimable until escrow creation succeeds","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"agentSelectionMode":{"description":"Agent selection mode. Automatically determined based on agentId presence","example":"direct","allOf":[{"$ref":"#/components/schemas/AgentSelectionMode"}]},"beneficiaryId":{"type":"string","description":"Beneficiary Nostr public key for the swap requester as a 64-character hex string. This is supplied by the external swap client and is not a local Minmo user ID.","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","pattern":"^[0-9a-fA-F]{64}$"}},"required":["type","fiatCurrency","paymentChannel","beneficiaryId"]},"SwapClaimDto":{"type":"object","properties":{"lightningInvoice":{"type":"string","description":"Lightning invoice that specifies how the claiming agent should be paid out in sats. Required for OFFRAMP swaps unless the claiming agent has a Lightning address configured in their settings, in which case it's resolved into a fresh invoice at settlement time.","example":"lnbc1500000n1pwmf6n2pp5z8x8r7x9mfwxv8zh3ng7tfkg0l9wzf2gctqtn4e8f4m9f0w3s8qdqqcqzpgxqyz5vqsp5c9d4c02mkdkw0n8a73zq59w0s7m4e0r2q3fj9qp7mex7hz7p8us9qyyssqv7t6psxqf3d4p6kpnm0ga0nkj6b6f6x6xnu7n7n9l6f4hs8t9nmeqgj4z0fsvy9rt5kag42caxu2q0f4w2cfc8d8waz27aew60nfrg3uj4lclp5q2jqq2z4vng"}}},"ConfirmationRole":{"type":"string","enum":["user","agent"],"description":"Role of the party confirming the payment (USER or AGENT)"},"ConfirmSwapDto":{"type":"object","properties":{"role":{"description":"Role of the party confirming the payment (USER or AGENT)","example":"user","allOf":[{"$ref":"#/components/schemas/ConfirmationRole"}]},"beneficiaryId":{"type":"string","description":"Beneficiary Nostr public key for authorization.","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","pattern":"^[0-9a-fA-F]{64}$"}},"required":["role"]},"DisputeSwapDto":{"type":"object","properties":{"reason":{"type":"string","description":"Detailed reason for disputing the swap","example":"Payment was not received after 48 hours","minLength":10,"maxLength":1000},"evidence":{"type":"object","description":"Supporting evidence for the dispute (screenshots, transaction IDs, etc.)","example":{"screenshots":["base64_encoded_image_1","base64_encoded_image_2"],"transactionReference":"TXN123456","additionalNotes":"Contacted support multiple times"}},"beneficiaryId":{"type":"string","description":"Beneficiary Nostr public key for authorization.","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","pattern":"^[0-9a-fA-F]{64}$"}},"required":["reason"]},"SubmitPaymentProofDto":{"type":"object","properties":{"proof":{"type":"string","description":"Payment proof (transaction ID, receipt number, confirmation code, etc.)","example":"TXN-2024-001234-CONFIRMED","minLength":5,"maxLength":500},"evidence":{"type":"object","description":"Additional evidence or metadata supporting the payment proof","example":{"bankStatement":"base64_encoded_pdf","timestamp":"2024-01-15T10:30:00Z","paymentMethod":"wire_transfer"}}},"required":["proof"]},"SubmitDisputeEvidenceDto":{"type":"object","properties":{"evidence":{"type":"object","description":"Additional evidence for the dispute including screenshots, logs, or communication records","example":{"communicationLogs":["email1.txt","chat_transcript.txt"],"bankConfirmation":"CONF-123456","timeline":"Payment sent at 10:00 AM, confirmed by bank at 10:15 AM"}},"documentProof":{"type":"string","description":"Bank statements, transaction records, or other documents (base64 encoded)","example":"JVBERi0xLjQKJeLjz9MKNCAwIG9iago...","maxLength":10485760}},"required":["evidence"]},"ExecuteRefundDto":{"type":"object","properties":{"destination":{"type":"object","description":"Bitcoin refund destination details for executing a refund. Must be either a Lightning invoice or an on-chain Bitcoin address. Fiat payment details are not allowed here.","example":{"lightningInvoice":"lnbc1500000n1pwmf6n2pp5z8x8r7x9mfwxv8zh3ng7tfkg0l9wzf2gctqtn4e8f4m9f0w3s8qdqqcqzpgxqyz5vqsp5c9d4c02mkdkw0n8a73zq59w0s7m4e0r2q3fj9qp7mex7hz7p8us9qyyssqv7t6psxqf3d4p6kpnm0ga0nkj6b6f6x6xnu7n7n9l6f4hs8t9nmeqgj4z0fsvy9rt5kag42caxu2q0f4w2cfc8d8waz27aew60nfrg3uj4lclp5q2jqq2z4vng","onChainAddress":"bc1qpke5447yy82sxjj0w25eut2kn0uge4ux4zskrc6jjng55g2fgukskd7kdz"}},"beneficiaryId":{"type":"string","description":"Beneficiary Nostr public key for authorization when the refund is going to the user.","example":"a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2","pattern":"^[0-9a-fA-F]{64}$"}},"required":["destination"]},"TransferSwapDto":{"type":"object","properties":{"newAgentId":{"type":"string","description":"UUID of the new agent to transfer the swap to","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"reason":{"type":"string","description":"Detailed reason for transferring the swap to another agent","example":"Original agent unavailable due to technical issues","minLength":10,"maxLength":500}},"required":["newAgentId","reason"]},"AgentStatus":{"type":"string","enum":["active","inactive","suspended"]},"AgentLimitsResponse":{"type":"object","properties":{"min":{"type":"string","description":"Minimum transaction amount in satoshis","example":"100000"},"max":{"type":"string","description":"Maximum transaction amount in satoshis","example":"10000000"},"daily":{"type":"string","description":"Daily volume limit in satoshis","example":"100000000"}},"required":["min","max","daily"]},"AgentMarginsResponse":{"type":"object","properties":{"onrampBp":{"type":"number","description":"Onramp margin in basis points","example":250},"offrampBp":{"type":"number","description":"Offramp margin in basis points","example":300}},"required":["onrampBp","offrampBp"]},"AgentMetricsResponse":{"type":"object","properties":{"rating":{"type":"number","description":"Agent's average rating (1.0 to 5.0)","example":4.5,"minimum":1,"maximum":5},"completedSwaps":{"type":"number","description":"Total number of completed swaps","example":150},"responseTime":{"type":"number","description":"Average response time in seconds","example":120}},"required":["rating","completedSwaps","responseTime"]},"AgentUserResponse":{"type":"object","properties":{"id":{"type":"string","description":"User ID associated with the agent","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"email":{"type":"string","description":"Email address of the agent user","example":"agent@example.com","format":"email"},"status":{"type":"string","description":"User account status","example":"active"},"metadata":{"type":"object","description":"Additional user metadata","example":{"verified":true,"kycLevel":2}}},"required":["id","email","status"]},"AgentResponse":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the agent","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"isAutomated":{"type":"boolean","description":"Whether the agent is automated","example":false},"status":{"description":"Current status of the agent","example":"active","allOf":[{"$ref":"#/components/schemas/AgentStatus"}]},"supportedCurrencies":{"type":"array","description":"List of currencies the agent supports","example":["USD","KES"],"items":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"]}},"supportedChannels":{"type":"array","description":"List of payment channels the agent supports","example":["bank_transfer","mpesa_phone"],"items":{"type":"string","enum":["mpesa_phone","mpesa_till","mpesa_paybill","airtel_money","airtel_money_till","tnm_mpamba","tnm_mpamba_merchant","bank_transfer","card","cash","lightning","onchain"]}},"limits":{"description":"Transaction limits for the agent","allOf":[{"$ref":"#/components/schemas/AgentLimitsResponse"}]},"margins":{"description":"Margin rates for different swap types","allOf":[{"$ref":"#/components/schemas/AgentMarginsResponse"}]},"metrics":{"description":"Performance metrics for the agent","allOf":[{"$ref":"#/components/schemas/AgentMetricsResponse"}]},"operatingHours":{"type":"object","description":"Operating hours configuration","example":{"monday":{"start":"09:00","end":"17:00"},"timezone":"UTC"}},"liquidity":{"description":"Liquidity information per currency","type":"array","items":{"type":"string"}},"user":{"$ref":"#/components/schemas/AgentUserResponse"},"paymentDetails":{"type":"object","description":"Configured payment details per supported channel"},"settings":{"type":"object","description":"Agent settings and preferences"},"currencyChannels":{"type":"object","description":"Currency-centric payment config"},"teamAssociation":{"type":"object","description":"Mini-local team association metadata"}},"required":["id","isAutomated","status","supportedCurrencies","supportedChannels","limits","margins"]},"PaginatedAgentsResponse":{"type":"object","properties":{"agents":{"description":"Array of agent records","type":"array","items":{"$ref":"#/components/schemas/AgentResponse"}},"total":{"type":"number","description":"Total number of agents matching the query","example":50},"totalAll":{"type":"number","description":"Total number of agents visible to the requester before filters","example":120},"page":{"type":"number","description":"Current page number","example":1},"limit":{"type":"number","description":"Number of items per page","example":20}},"required":["agents","total","totalAll","page","limit"]},"ActivateAgentTeamReferralDto":{"type":"object","properties":{"referralCode":{"type":"string","description":"Team referral code used to confirm the agent's team association before swap links are shown","example":"MMAB1C2D"}},"required":["referralCode"]},"UpdateAvailabilityDto":{"type":"object","properties":{"status":{"description":"New availability status for the agent","example":"active","allOf":[{"$ref":"#/components/schemas/AgentStatus"}]},"agentId":{"type":"string","description":"Agent ID to update (admin only). If not provided, updates the authenticated user's agent profile","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"}},"required":["status"]},"ValidateAgentDto":{"type":"object","properties":{"amount":{"type":"string","description":"Transaction amount in satoshis to validate against agent min/max limits","example":"100000","pattern":"^[0-9]+$"},"currency":{"description":"Currency for the transaction","example":"USD","allOf":[{"$ref":"#/components/schemas/Currency"}]},"paymentChannel":{"description":"Payment channel for the transaction","example":"bank_transfer","allOf":[{"$ref":"#/components/schemas/PaymentChannel"}]}},"required":["amount","currency","paymentChannel"]},"UpdateAgentDto":{"type":"object","properties":{"supportedCurrencies":{"type":"array","description":"Updated list of supported currencies","example":["USD","KES"],"items":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"]}},"currencyChannels":{"type":"object","description":"Currency-centric payment config (preferred). When provided, legacy fields are derived."},"supportedChannels":{"type":"array","description":"Updated list of supported payment channels","example":["bank_transfer","mpesa_phone"],"items":{"type":"string","enum":["mpesa_phone","mpesa_till","mpesa_paybill","airtel_money","airtel_money_till","tnm_mpamba","tnm_mpamba_merchant","bank_transfer","card","cash","lightning","onchain"]}},"minTransactionAmount":{"type":"string","description":"Updated minimum transaction amount in satoshis","example":"500000","pattern":"^[0-9]+$"},"maxTransactionAmount":{"type":"string","description":"Updated maximum transaction amount in satoshis","example":"5000000","pattern":"^[0-9]+$"},"dailyVolumeLimit":{"type":"string","description":"Updated daily volume limit in satoshis","example":"50000000","pattern":"^[0-9]+$"},"onrampMarginBp":{"type":"number","description":"Updated onramp margin in basis points","example":200,"minimum":0,"maximum":10000},"offrampMarginBp":{"type":"number","description":"Updated offramp margin in basis points","example":250,"minimum":0,"maximum":10000},"operatingHours":{"type":"object","description":"Updated operating hours configuration","example":{"monday":{"start":"09:00","end":"17:00"},"timezone":"UTC"}},"settings":{"type":"object","description":"Updated agent settings and preferences","example":{"autoAccept":true,"maxConcurrentSwaps":10,"publiclyVisible":false,"lightningAddress":"agent@example.com","walletPreference":"external"}},"paymentDetails":{"type":"object","description":"Updated payment details keyed by payment channel. Every supported channel must have valid details."}}},"AgentSwapHistoryResponse":{"type":"object","properties":{"swaps":{"description":"Array of swap records handled by the agent","type":"array","items":{"$ref":"#/components/schemas/SwapResponse"}},"total":{"type":"number","description":"Total number of swaps","example":100},"page":{"type":"number","description":"Current page number","example":1},"limit":{"type":"number","description":"Number of items per page","example":20}},"required":["swaps","total","page","limit"]},"AgentTeamAssociationStatus":{"type":"string","enum":["pending","active","removed"],"description":"Primary team association status"},"AgentTeamAssociationVisibility":{"type":"string","enum":["team","private"],"description":"Primary team association visibility"},"SetAgentTeamAssociationDto":{"type":"object","properties":{"status":{"description":"Primary team association status","example":"active","allOf":[{"$ref":"#/components/schemas/AgentTeamAssociationStatus"}]},"visibility":{"description":"Primary team association visibility","example":"team","allOf":[{"$ref":"#/components/schemas/AgentTeamAssociationVisibility"}]},"metadata":{"type":"object","description":"Optional association metadata","example":{"source":"console"}}}},"AgentActivityScopeResponse":{"type":"object","properties":{"type":{"type":"string","enum":["platform","team"]},"teamId":{"type":"string","description":"Team ID for team-scoped activity"}},"required":["type"]},"AgentActivitySwapSummary":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier of the swap","example":"550e8400-e29b-41d4-a716-446655440000"},"reference":{"type":"string","description":"Human-readable swap reference","example":"SWAP-2024-001234"},"type":{"allOf":[{"$ref":"#/components/schemas/SwapType"}]},"state":{"allOf":[{"$ref":"#/components/schemas/SwapState"}]},"agentId":{"type":"object","description":"Agent ID assigned to the swap","nullable":true},"fiatAmount":{"type":"string","description":"Fiat amount in smallest units"},"fiatCurrency":{"allOf":[{"$ref":"#/components/schemas/Currency"}]},"bitcoinAmount":{"type":"string","description":"Bitcoin amount in satoshis"},"paymentChannel":{"allOf":[{"$ref":"#/components/schemas/PaymentChannel"}]},"createdAt":{"type":"string","description":"Created timestamp","format":"date-time"},"completedAt":{"type":"string","description":"Completed timestamp","format":"date-time"}},"required":["id","reference","type","state","agentId","fiatAmount","fiatCurrency","bitcoinAmount","paymentChannel","createdAt"]},"AgentActivityMetricsResponse":{"type":"object","properties":{"totalSwaps":{"type":"number","description":"Total swaps in scope","example":120},"activeSwaps":{"type":"number","description":"Active swaps in scope","example":8},"completedSwaps":{"type":"number","description":"Completed swaps in scope","example":95},"totalFiatVolume":{"type":"number","description":"Total fiat volume in scope","example":1230000},"completedBtcVolume":{"type":"number","description":"Total settled BTC volume in satoshis for completed swaps","example":2500000}},"required":["totalSwaps","activeSwaps","completedSwaps","totalFiatVolume","completedBtcVolume"]},"AgentActivityResponse":{"type":"object","properties":{"scope":{"$ref":"#/components/schemas/AgentActivityScopeResponse"},"agents":{"type":"array","items":{"$ref":"#/components/schemas/AgentResponse"}},"swaps":{"type":"array","items":{"$ref":"#/components/schemas/AgentActivitySwapSummary"}},"metrics":{"$ref":"#/components/schemas/AgentActivityMetricsResponse"},"page":{"type":"number","description":"Current page number","example":1},"limit":{"type":"number","description":"Number of recent swaps returned","example":20}},"required":["scope","agents","swaps","metrics","page","limit"]},"ValidateLiquidityDto":{"type":"object","properties":{"agentId":{"type":"string","description":"Agent ID to validate liquidity for","example":"550e8400-e29b-41d4-a716-446655440000","format":"uuid"},"currency":{"description":"Currency to validate liquidity for","example":"USD","allOf":[{"$ref":"#/components/schemas/Currency"}]},"amount":{"type":"string","description":"Amount to validate. For BTC: satoshis (e.g., '50000000' for 0.5 BTC). For fiat: decimal amount (e.g., '500.00' for $500)","examples":{"btc":{"summary":"Bitcoin (satoshis)","value":"50000000"},"usd":{"summary":"US Dollar (decimal)","value":"500.00"}}}},"required":["agentId","currency","amount"]},"CreateWalletConnectionDto":{"type":"object","properties":{}},"CreatePayStoreDto":{"type":"object","properties":{"name":{"type":"string","example":"Acme Checkout","maxLength":128},"defaultCurrency":{"type":"string","example":"KES","pattern":"^[A-Z]{3}$"},"website":{"type":"string","example":"https://acme.example"},"supportUrl":{"type":"string","example":"https://acme.example/support"},"brandColor":{"type":"string","example":"#f97316","pattern":"^#[0-9a-fA-F]{6}$"}},"required":["name"]},"ConnectPayWalletDto":{"type":"object","properties":{"walletId":{"type":"string","example":"wallet_1","maxLength":160}},"required":["walletId"]},"CreatePayInvoiceDto":{"type":"object","properties":{"amount":{"type":"string","example":"1500.00","description":"Positive decimal amount with at most 18 decimal places"},"currency":{"type":"string","example":"KES","pattern":"^[A-Z]{3}$"},"reference":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":500},"expirationMinutes":{"type":"number","minimum":1,"maximum":10080}},"required":["amount","currency"]},"VerifyReferralCodeDto":{"type":"object","properties":{"code":{"type":"string","description":"The referral code to verify","example":"MMAB1C2D"}},"required":["code"]},"VerifyReferralCodeResponse":{"type":"object","properties":{"valid":{"type":"boolean","description":"Whether the code is valid","example":true},"active":{"type":"boolean","description":"Whether the code is active","example":true},"scope":{"type":"string","enum":["system","team"]},"allowedUses":{"type":"array","items":{"type":"string","enum":["agent_invite","partner_member_signup"]}},"teamDisplayName":{"type":"string"},"error":{"type":"string","description":"Error message (if invalid)","example":"Invalid referral code"}},"required":["valid","active"]},"CreateReferralCodeDto":{"type":"object","properties":{"allowedUses":{"type":"array","description":"Audience allowed to use the new referral code","example":["agent_invite"],"items":{"type":"string","enum":["agent_invite","partner_member_signup"]}}}},"RegisterPushTokenDto":{"type":"object","properties":{"token":{"type":"string","example":"ExponentPushToken[xxxxxxxxxxxxxxxxxxxxxx]"},"platform":{"type":"string","enum":["ios","android","web"]},"deviceId":{"type":"string","example":"device-uuid-12345"}},"required":["token","platform"]},"AccountingSourceReferenceDto":{"type":"object","properties":{"type":{"type":"string","enum":["wallet","psp_connection"]},"id":{"type":"string","maxLength":160}},"required":["type","id"]},"CreateReportingTemplateDto":{"type":"object","properties":{"displayName":{"type":"string","maxLength":160},"source":{"$ref":"#/components/schemas/AccountingSourceReferenceDto"},"reportType":{"type":"string","enum":["transaction_history","general_ledger"]}},"required":["displayName","source","reportType"]},"CreateAccountingReportDto":{"type":"object","properties":{"source":{"$ref":"#/components/schemas/AccountingSourceReferenceDto"},"reportType":{"type":"string","enum":["transaction_history","general_ledger"]},"periodStart":{"type":"string","format":"date-time"},"periodEnd":{"type":"string","format":"date-time"}},"required":["source","reportType","periodStart","periodEnd"]},"CreateOwnerPspConnectionDto":{"type":"object","properties":{"provider":{"type":"string","enum":["safaricom_daraja"]},"environment":{"type":"string","enum":["sandbox","production"]},"displayName":{"type":"string","example":"Daraja main","maxLength":160},"providerAccountReference":{"type":"string","example":"174379","maxLength":255},"connectionConfiguration":{"type":"object","additionalProperties":true,"description":"Non-secret provider product and account configuration"},"credentials":{"type":"object","additionalProperties":true,"description":"Provider credentials encrypted by Minmo at rest"}},"required":["provider","environment","displayName","providerAccountReference","credentials"]},"RotatePspCredentialsDto":{"type":"object","properties":{"credentials":{"type":"object","additionalProperties":true}},"required":["credentials"]},"CreateDelegatedPspConnectionDto":{"type":"object","properties":{"authorizedEntityType":{"type":"string","enum":["partner","agent"],"example":"agent"},"authorizedEntityId":{"type":"string","maxLength":160},"displayName":{"type":"string","example":"Agent collections","maxLength":160},"capabilities":{"type":"array","items":{"type":"string","enum":["collection_create","disbursement_create","payment_read","webhook_receive"]}},"currencyScope":{"type":"array","items":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"]}},"limits":{"type":"object","example":{"maxAmountMinor":"100000"}},"effectiveUntil":{"type":"string","format":"date-time"}},"required":["authorizedEntityType","authorizedEntityId","displayName","capabilities","currencyScope"]},"RevokePspConnectionDto":{"type":"object","properties":{"reason":{"type":"string","maxLength":500}},"required":["reason"]},"CreatePspCollectionDto":{"type":"object","properties":{"initiatingEntityType":{"type":"string","enum":["partner","agent"]},"initiatingEntityId":{"type":"string","maxLength":160},"amountMinor":{"type":"string","example":"125000","pattern":"^[1-9]\\d*$"},"currency":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"example":"KES"},"exponent":{"type":"number","example":2,"minimum":0,"maximum":18},"paymentMethod":{"type":"string","enum":["daraja_stk_push","daraja_send_money","daraja_buy_goods","daraja_paybill"]},"channelData":{"type":"object","additionalProperties":true},"reference":{"type":"string","example":"ORDER-1042","maxLength":12}},"required":["initiatingEntityType","initiatingEntityId","amountMinor","currency","exponent","paymentMethod","channelData","reference"]},"CreatePspDisbursementDto":{"type":"object","properties":{"initiatingEntityType":{"type":"string","enum":["partner","agent"]},"initiatingEntityId":{"type":"string","maxLength":160},"amountMinor":{"type":"string","example":"125000","pattern":"^[1-9]\\d*$"},"currency":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"example":"KES"},"exponent":{"type":"number","example":2,"minimum":0,"maximum":18},"paymentMethod":{"type":"string","enum":["daraja_stk_push","daraja_send_money","daraja_buy_goods","daraja_paybill"]},"channelData":{"type":"object","additionalProperties":true},"reference":{"type":"string","example":"PAYOUT-1042","maxLength":32}},"required":["initiatingEntityType","initiatingEntityId","amountMinor","currency","exponent","paymentMethod","channelData","reference"]},"CreatePspReconciliationDto":{"type":"object","properties":{"connectionId":{"type":"string","format":"uuid"},"currency":{"type":"string","enum":["BTC","GBP","INR","KES","MUR","MWK","MZN","NGN","PKR","USDT","USD","ZAR","UNRECOGNIZED"],"example":"KES"},"exponent":{"type":"number","example":2,"minimum":0,"maximum":18},"evidencePeriodStart":{"type":"string","format":"date-time"},"evidencePeriodEnd":{"type":"string","format":"date-time"}},"required":["connectionId","currency","exponent","evidencePeriodStart","evidencePeriodEnd"]},"ResolvePspReconciliationItemDto":{"type":"object","properties":{"action":{"type":"string","enum":["confirm_existing_match","link_payment","record_accounting_correction"]},"reason":{"type":"string","maxLength":1000},"evidenceReference":{"type":"string","maxLength":1000},"approvalReference":{"type":"string","maxLength":255},"paymentId":{"type":"string","format":"uuid"},"resolutionJournalId":{"type":"string","format":"uuid"}},"required":["action","reason","evidenceReference","approvalReference"]},"TeamSubscriptionDto":{"type":"object","properties":{"status":{"type":"string","enum":["trialing","active","past_due","grace","paused","canceled"]},"interval":{"type":"string","enum":["monthly","yearly"]},"provider":{"type":"string","description":"Billing provider identifier."},"providerCustomerId":{"type":"string"},"providerSubscriptionId":{"type":"string"},"currentPeriodStart":{"type":"string"},"currentPeriodEnd":{"type":"string"},"trialEndsAt":{"type":"string"},"cancelAt":{"type":"string"},"canceledAt":{"type":"string"}}},"SetTeamPlanDto":{"type":"object","properties":{"planCode":{"type":"string","enum":["wallet_partner","integration_partner","operating_partner"]},"subscription":{"$ref":"#/components/schemas/TeamSubscriptionDto"},"effectiveFrom":{"type":"string","description":"ISO timestamp recorded as effectiveFrom and syncedAt. Defaults to now."}},"required":["planCode"]},"SetEntitlementOverrideDto":{"type":"object","properties":{"status":{"type":"string","enum":["active","trialing","grace","past_due","suspended","expired"]},"reason":{"type":"string","description":"Why the override exists. Recorded in the audit trail."},"effectiveFrom":{"type":"string"},"effectiveUntil":{"type":"string"}},"required":["status"]},"CreateSubscriptionInvoiceDto":{"type":"object","properties":{"planCode":{"type":"string","enum":["wallet_partner","integration_partner","operating_partner"]},"interval":{"type":"string","enum":["monthly","yearly"],"description":"Defaults to monthly."},"period":{"type":"string","description":"Billing period: YYYY-MM for monthly, YYYY for yearly. Defaults to the current period."}},"required":["planCode"]},"NotificationPreferenceResponse":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"notificationType":{"type":"string","enum":["otc.swap.created","otc.swap.escrow.pending","otc.swap.escrow.locked","otc.swap.claimed","otc.swap.payment.instructed","otc.swap.payment.pending","otc.swap.payment.submitted","otc.swap.payment.confirmed.user","otc.swap.payment.confirmed.agent","otc.swap.confirmation.pending","otc.swap.completed","otc.swap.cancelled","otc.swap.refund.initiated","otc.swap.refund.failed","otc.swap.disputed","otc.swap.dispute.evidence.collection","otc.swap.dispute.internal.review","otc.swap.dispute.review","otc.swap.dispute.resolved","otc.swap.refunded","otc.swap.expired","otc.swap.fiat.sender.timeout","otc.swap.fiat.receiver.timeout","otc.swap.transferred.to.backup","otc.agent.registered","otc.agent.updated","otc.agent.availability.changed","otc.agent.team.associated","otc.agent.team.removed","otc.rate.quoted","otc.rate.updated","otc.rate.expired","pay.invoice.created","pay.invoice.processing","pay.invoice.settled","pay.invoice.expired","pay.invoice.invalid","pay.store.connected","pay.store.connection.failed","wallet.synced","wallet.deposits.discovered","wallet.deposits.unclaimed","wallet.deposits.claimed","wallet.payment.pending","wallet.payment.succeeded","wallet.payment.failed","escrow.reference.issued","escrow.funding.confirmed","escrow.dispute.resolution.recorded","escrow.released","escrow.refunded","escrow.expired","psp.connection.created","psp.connection.activated","psp.connection.suspended","psp.connection.revoked","psp.payment.created","psp.payment.submitted","psp.payment.pending","psp.payment.succeeded","psp.payment.failed","psp.payment.outcome.unknown","psp.payment.cancelled","psp.reconciliation.completed","psp.reconciliation.exception.detected","psp.reconciliation.exception.resolved"]},"enabled":{"type":"boolean"},"channels":{"type":"object","example":{"push":true,"sse":true}},"settings":{"type":"object"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","userId","notificationType","enabled","channels","createdAt","updatedAt"]},"UpdatePreferenceDto":{"type":"object","properties":{"channels":{"type":"object","example":{"push":true,"sse":true}},"enabled":{"type":"boolean","default":true},"settings":{"type":"object","example":{"quietHours":{"start":"22:00","end":"07:00"}}}},"required":["channels"]},"BulkUpdateUserRolesDto":{"type":"object","properties":{"roles":{"type":"array","description":"Direct Minmo user roles to assign. Team roles are managed through team-specific membership endpoints.","example":["minmo_partner"],"items":{"type":"string","enum":["minmo_admin","minmo_partner","minmo_agent"]}},"userIds":{"description":"Local Minmo user IDs to update","example":["7b88676f-0d9a-4434-ae4b-529a047e592a"],"type":"array","items":{"type":"array"}}},"required":["roles","userIds"]},"UpdateUserProfileDto":{"type":"object","properties":{"email":{"type":"object","description":"User email address","example":"user@example.com","nullable":true},"status":{"type":"string","description":"User status","enum":["pending","active","suspended"],"example":"active"},"firstName":{"type":"string","description":"First name stored in Mini user metadata","example":"John"},"lastName":{"type":"string","description":"Last name stored in Mini user metadata","example":"Doe"}}},"UpdateUserRolesDto":{"type":"object","properties":{"roles":{"type":"array","description":"Direct Minmo user roles to assign. Team roles are managed through team-specific membership endpoints.","example":["minmo_partner"],"items":{"type":"string","enum":["minmo_admin","minmo_partner","minmo_agent"]}}},"required":["roles"]}}}}