Files
CashumintsAPI/src/docs/openapi.js
2025-12-19 23:56:07 -03:00

2300 lines
90 KiB
JavaScript

/**
* OpenAPI 3.0 Specification
*
* Full API documentation for Cashumints.space
*/
export const openApiSpec = {
openapi: '3.0.3',
info: {
title: 'Cashumints.space API',
description: `
# Cashumints.space API
A decentralized observability, discovery, and reputation API for the Cashu mint ecosystem.
## Overview
This API provides:
- **Mint Discovery** - Track Cashu mints across the ecosystem
- **Uptime Monitoring** - Continuous probing with historical data
- **Metadata Tracking** - NUT-06 compliant metadata with change history
- **Nostr Reviews** - NIP-87 based review ingestion from relays
- **Trust Scores** - Transparent, explainable reputation scoring
- **Analytics** - Pageviews, trending, and popularity metrics
## Key Concepts
### Mint Identity
Each mint is identified by a stable \`mint_id\` (UUID). A mint can have multiple URLs (clearnet, Tor, mirrors). All URLs resolve to the same mint identity.
### Mint Status
Mints cycle through states: \`unknown\`\`online\`\`degraded\`\`offline\`\`abandoned\`
### Trust Scores
Scores range from 0-100 and are computed from:
- Uptime reliability (40 points max)
- Response speed (25 points max)
- Nostr reviews (20 points max)
- Identity completeness (10 points max)
- Penalties for instability (up to -15 points)
## Authentication
This is a public, read-only API. No authentication required for read access.
## Rate Limiting
100 requests per minute per IP. Rate limit headers are included in responses.
## Admin API
Admin endpoints require the \`X-Admin-Api-Key\` header. All admin actions are audited. Admin operations never delete raw data - they annotate, correct routing, or trigger recomputation.
`,
version: '1.0.0',
contact: {
name: 'Cashumints.space',
url: 'https://cashumints.space'
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT'
}
},
externalDocs: {
description: 'Cashu Protocol Documentation',
url: 'https://docs.cashu.space'
},
servers: [{
url: '/v1',
description: 'Current server (relative)'
},
{
url: 'https://api.cashumints.space/v1',
description: 'Production API'
},
{
url: 'http://localhost:3000/v1',
description: 'Local development'
}
],
tags: [{
name: 'System',
description: 'Health checks and system statistics'
},
{
name: 'Mints',
description: 'Mint discovery and listing'
},
{
name: 'Mint Details',
description: 'Detailed mint information'
},
{
name: 'Metadata',
description: 'NUT-06 metadata endpoints'
},
{
name: 'Uptime',
description: 'Uptime and reliability metrics'
},
{
name: 'Trust',
description: 'Trust scores and reputation'
},
{
name: 'Reviews',
description: 'Nostr-based reviews (NIP-87)'
},
{
name: 'Analytics',
description: 'Pageviews and popularity'
},
{
name: 'Admin',
description: 'Admin-only endpoints (requires X-Admin-Api-Key header)'
}
],
paths: {
'/health': {
get: {
tags: ['System'],
summary: 'Health check',
description: 'Returns the health status of the API',
operationId: 'getHealth',
responses: {
200: {
description: 'API is healthy',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/HealthResponse' }
}
}
},
503: {
description: 'API is unhealthy',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/HealthResponse' }
}
}
}
}
}
},
'/stats': {
get: {
tags: ['System'],
summary: 'System statistics',
description: 'Returns overall system statistics including mint counts, activity, and trending data',
operationId: 'getStats',
responses: {
200: {
description: 'System statistics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/StatsResponse' }
}
}
}
}
}
},
'/reviews': {
get: {
tags: ['Reviews'],
summary: 'Global reviews feed',
description: 'Returns all reviews across the ecosystem with optional filtering',
operationId: 'getGlobalReviews',
parameters: [{
name: 'mint_id',
in: 'query',
description: 'Filter by mint ID',
schema: { type: 'string', format: 'uuid' }
},
{
name: 'mint_url',
in: 'query',
description: 'Filter by mint URL',
schema: { type: 'string' }
},
{
name: 'since',
in: 'query',
description: 'Unix timestamp - only reviews after this time',
schema: { type: 'integer' }
},
{
name: 'until',
in: 'query',
description: 'Unix timestamp - only reviews before this time',
schema: { type: 'integer' }
},
{
name: 'limit',
in: 'query',
description: 'Maximum number of results',
schema: { type: 'integer', default: 50, maximum: 200 }
},
{
name: 'offset',
in: 'query',
description: 'Number of results to skip',
schema: { type: 'integer', default: 0 }
}
],
responses: {
200: {
description: 'Review list',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/GlobalReviewsResponse' }
}
}
}
}
}
},
'/analytics/uptime': {
get: {
tags: ['Analytics'],
summary: 'Ecosystem uptime analytics',
description: 'Returns ecosystem-wide uptime and reliability metrics',
operationId: 'getUptimeAnalytics',
parameters: [{
name: 'window',
in: 'query',
description: 'Time window for analytics',
schema: {
type: 'string',
enum: ['24h', '7d', '30d'],
default: '24h'
}
}],
responses: {
200: {
description: 'Uptime analytics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/UptimeAnalytics' }
}
}
}
}
}
},
'/analytics/versions': {
get: {
tags: ['Analytics'],
summary: 'Version distribution analytics',
description: 'Returns mint version distribution across the ecosystem',
operationId: 'getVersionAnalytics',
responses: {
200: {
description: 'Version analytics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/VersionAnalytics' }
}
}
}
}
}
},
'/analytics/nuts': {
get: {
tags: ['Analytics'],
summary: 'NUT support analytics',
description: 'Returns NUT support distribution across all mints',
operationId: 'getNutsAnalytics',
responses: {
200: {
description: 'NUT analytics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/NutsAnalytics' }
}
}
}
}
}
},
'/mints/trending': {
get: {
tags: ['Mints'],
summary: 'Get trending mints',
description: 'Returns mints ranked by view velocity (popularity)',
operationId: 'getTrendingMints',
parameters: [{
name: 'window',
in: 'query',
description: 'Time window for trending calculation',
schema: {
type: 'string',
enum: ['24h', '7d'],
default: '7d'
}
},
{
name: 'limit',
in: 'query',
description: 'Maximum number of results',
schema: { type: 'integer', default: 10, maximum: 50 }
}
],
responses: {
200: {
description: 'Trending mints',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/TrendingMintsResponse' }
}
}
}
}
}
},
'/mints': {
get: {
tags: ['Mints'],
summary: 'List all mints',
description: 'Returns a paginated list of all tracked mints with optional filtering',
operationId: 'listMints',
parameters: [{
name: 'status',
in: 'query',
description: 'Filter by mint status',
schema: {
type: 'string',
enum: ['unknown', 'online', 'degraded', 'offline', 'abandoned']
}
},
{
name: 'limit',
in: 'query',
description: 'Maximum number of results',
schema: { type: 'integer', default: 100, maximum: 500 }
},
{
name: 'offset',
in: 'query',
description: 'Number of results to skip',
schema: { type: 'integer', default: 0 }
},
{
name: 'sort_by',
in: 'query',
description: 'Sort field',
schema: {
type: 'string',
enum: ['created_at', 'updated_at', 'name', 'trust_score'],
default: 'created_at'
}
},
{
name: 'sort_order',
in: 'query',
description: 'Sort order',
schema: { type: 'string', enum: ['asc', 'desc'], default: 'desc' }
}
],
responses: {
200: {
description: 'List of mints',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintListResponse' }
}
}
}
}
}
},
'/mints/submit': {
post: {
tags: ['Mints'],
summary: 'Submit a new mint',
description: 'Submit a mint URL for tracking. The mint will be probed and added to the index.',
operationId: 'submitMint',
requestBody: {
required: true,
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintSubmission' }
}
}
},
responses: {
201: {
description: 'Mint submitted successfully',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintSubmissionResponse' }
}
}
},
400: {
description: 'Invalid URL or submission error',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Error' }
}
}
}
}
}
},
'/mints/{mint_id}': {
get: {
tags: ['Mint Details'],
summary: 'Get mint by ID',
description: 'Returns detailed information about a specific mint',
operationId: 'getMintById',
parameters: [
{ $ref: '#/components/parameters/mintId' }
],
responses: {
200: {
description: 'Mint details',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Mint' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url': {
get: {
tags: ['Mint Details'],
summary: 'Get mint by URL',
description: 'Returns detailed information about a mint by its URL',
operationId: 'getMintByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' }
],
responses: {
200: {
description: 'Mint details',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Mint' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/urls': {
get: {
tags: ['Mint Details'],
summary: 'Get mint URLs',
description: 'Returns all known URLs for a mint (clearnet, Tor, mirrors)',
operationId: 'getMintUrls',
parameters: [
{ $ref: '#/components/parameters/mintId' }
],
responses: {
200: {
description: 'Mint URLs',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintUrlsResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/status': {
get: {
tags: ['Mint Details'],
summary: 'Get mint status',
description: 'Returns lightweight status information for quick checks',
operationId: 'getMintStatus',
parameters: [
{ $ref: '#/components/parameters/mintId' }
],
responses: {
200: {
description: 'Mint status',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintStatus' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/metadata': {
get: {
tags: ['Metadata'],
summary: 'Get mint metadata',
description: 'Returns NUT-06 compliant metadata for a mint',
operationId: 'getMintMetadata',
parameters: [
{ $ref: '#/components/parameters/mintId' }
],
responses: {
200: {
description: 'Mint metadata',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintMetadata' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/metadata/history': {
get: {
tags: ['Metadata'],
summary: 'Get metadata history',
description: 'Returns history of metadata changes for a mint',
operationId: 'getMintMetadataHistory',
parameters: [
{ $ref: '#/components/parameters/mintId' },
{
name: 'limit',
in: 'query',
description: 'Maximum number of history entries',
schema: { type: 'integer', default: 50 }
}
],
responses: {
200: {
description: 'Metadata history',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MetadataHistoryResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/uptime': {
get: {
tags: ['Uptime'],
summary: 'Get uptime statistics',
description: 'Returns uptime and reliability metrics for a mint',
operationId: 'getMintUptime',
parameters: [
{ $ref: '#/components/parameters/mintId' },
{
name: 'window',
in: 'query',
description: 'Time window for statistics',
schema: {
type: 'string',
enum: ['24h', '7d', '30d'],
default: '24h'
}
}
],
responses: {
200: {
description: 'Uptime statistics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/UptimeStats' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/uptime/timeseries': {
get: {
tags: ['Uptime'],
summary: 'Get uptime timeseries',
description: 'Returns time-bucketed uptime data for charting',
operationId: 'getMintUptimeTimeseries',
parameters: [
{ $ref: '#/components/parameters/mintId' },
{
name: 'window',
in: 'query',
description: 'Time window',
schema: {
type: 'string',
enum: ['24h', '7d', '30d'],
default: '24h'
}
},
{
name: 'bucket',
in: 'query',
description: 'Time bucket size',
schema: {
type: 'string',
enum: ['5m', '15m', '1h'],
default: '1h'
}
}
],
responses: {
200: {
description: 'Uptime timeseries',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/UptimeTimeseriesResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/incidents': {
get: {
tags: ['Uptime'],
summary: 'Get incidents',
description: 'Returns downtime incidents for a mint',
operationId: 'getMintIncidents',
parameters: [
{ $ref: '#/components/parameters/mintId' },
{
name: 'limit',
in: 'query',
description: 'Maximum number of incidents',
schema: { type: 'integer', default: 50 }
}
],
responses: {
200: {
description: 'Incident list',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/IncidentsResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/trust': {
get: {
tags: ['Trust'],
summary: 'Get trust score',
description: 'Returns the computed trust score with full breakdown',
operationId: 'getMintTrust',
parameters: [
{ $ref: '#/components/parameters/mintId' }
],
responses: {
200: {
description: 'Trust score',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/TrustScore' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/reviews': {
get: {
tags: ['Reviews'],
summary: 'Get Nostr reviews',
description: 'Returns NIP-87 reviews from Nostr relays',
operationId: 'getMintReviews',
parameters: [
{ $ref: '#/components/parameters/mintId' },
{
name: 'limit',
in: 'query',
description: 'Maximum number of reviews',
schema: { type: 'integer', default: 50 }
},
{
name: 'offset',
in: 'query',
description: 'Number of reviews to skip',
schema: { type: 'integer', default: 0 }
}
],
responses: {
200: {
description: 'Review list',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/ReviewsResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/views': {
get: {
tags: ['Analytics'],
summary: 'Get pageview statistics',
description: 'Returns popularity metrics based on pageviews',
operationId: 'getMintViews',
parameters: [
{ $ref: '#/components/parameters/mintId' }
],
responses: {
200: {
description: 'Pageview statistics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/ViewStats' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/{mint_id}/features': {
get: {
tags: ['Mint Details'],
summary: 'Get derived features',
description: 'Returns features derived from metadata (supported NUTs, Bolt11 support, etc.)',
operationId: 'getMintFeatures',
parameters: [
{ $ref: '#/components/parameters/mintId' }
],
responses: {
200: {
description: 'Derived features',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintFeatures' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/urls': {
get: {
tags: ['Mint Details'],
summary: 'Get mint URLs by URL',
description: 'Returns all known URLs for a mint identified by URL',
operationId: 'getMintUrlsByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' }
],
responses: {
200: {
description: 'Mint URLs',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintUrlsResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/status': {
get: {
tags: ['Mint Details'],
summary: 'Get mint status by URL',
description: 'Returns lightweight status information by URL',
operationId: 'getMintStatusByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' }
],
responses: {
200: {
description: 'Mint status',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintStatus' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/metadata': {
get: {
tags: ['Metadata'],
summary: 'Get mint metadata by URL',
description: 'Returns NUT-06 compliant metadata for a mint by URL',
operationId: 'getMintMetadataByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' }
],
responses: {
200: {
description: 'Mint metadata',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintMetadata' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/metadata/history': {
get: {
tags: ['Metadata'],
summary: 'Get metadata history by URL',
description: 'Returns history of metadata changes for a mint by URL',
operationId: 'getMintMetadataHistoryByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' },
{
name: 'limit',
in: 'query',
description: 'Maximum number of history entries',
schema: { type: 'integer', default: 50 }
}
],
responses: {
200: {
description: 'Metadata history',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MetadataHistoryResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/uptime': {
get: {
tags: ['Uptime'],
summary: 'Get uptime statistics by URL',
description: 'Returns uptime and reliability metrics for a mint by URL',
operationId: 'getMintUptimeByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' },
{
name: 'window',
in: 'query',
description: 'Time window for statistics',
schema: {
type: 'string',
enum: ['24h', '7d', '30d'],
default: '24h'
}
}
],
responses: {
200: {
description: 'Uptime statistics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/UptimeStats' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/uptime/timeseries': {
get: {
tags: ['Uptime'],
summary: 'Get uptime timeseries by URL',
description: 'Returns time-bucketed uptime data for charting by URL',
operationId: 'getMintUptimeTimeseriesByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' },
{
name: 'window',
in: 'query',
description: 'Time window',
schema: {
type: 'string',
enum: ['24h', '7d', '30d'],
default: '24h'
}
},
{
name: 'bucket',
in: 'query',
description: 'Time bucket size',
schema: {
type: 'string',
enum: ['5m', '15m', '1h'],
default: '1h'
}
}
],
responses: {
200: {
description: 'Uptime timeseries',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/UptimeTimeseriesResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/incidents': {
get: {
tags: ['Uptime'],
summary: 'Get incidents by URL',
description: 'Returns downtime incidents for a mint by URL',
operationId: 'getMintIncidentsByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' },
{
name: 'limit',
in: 'query',
description: 'Maximum number of incidents',
schema: { type: 'integer', default: 50 }
}
],
responses: {
200: {
description: 'Incident list',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/IncidentsResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/trust': {
get: {
tags: ['Trust'],
summary: 'Get trust score by URL',
description: 'Returns the computed trust score with full breakdown by URL',
operationId: 'getMintTrustByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' }
],
responses: {
200: {
description: 'Trust score',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/TrustScore' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/reviews': {
get: {
tags: ['Reviews'],
summary: 'Get Nostr reviews by URL',
description: 'Returns NIP-87 reviews from Nostr relays by URL',
operationId: 'getMintReviewsByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' },
{
name: 'limit',
in: 'query',
description: 'Maximum number of reviews',
schema: { type: 'integer', default: 50 }
},
{
name: 'offset',
in: 'query',
description: 'Number of reviews to skip',
schema: { type: 'integer', default: 0 }
}
],
responses: {
200: {
description: 'Review list',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/ReviewsResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/views': {
get: {
tags: ['Analytics'],
summary: 'Get pageview statistics by URL',
description: 'Returns popularity metrics based on pageviews by URL',
operationId: 'getMintViewsByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' }
],
responses: {
200: {
description: 'Pageview statistics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/ViewStats' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/mints/by-url/features': {
get: {
tags: ['Mint Details'],
summary: 'Get derived features by URL',
description: 'Returns features derived from metadata by URL',
operationId: 'getMintFeaturesByUrl',
parameters: [
{ $ref: '#/components/parameters/mintUrl' }
],
responses: {
200: {
description: 'Derived features',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintFeatures' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
// ==========================================
// ADMIN ENDPOINTS
// ==========================================
'/admin/mints': {
post: {
tags: ['Admin'],
summary: 'Manually add a mint',
description: 'Add a mint to the system manually. Used for trusted bootstrap or recovery.',
operationId: 'adminCreateMint',
security: [{ AdminApiKey: [] }],
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['mint_url'],
properties: {
mint_url: { type: 'string', format: 'uri' },
notes: { type: 'string', description: 'Internal notes' }
}
}
}
}
},
responses: {
201: {
description: 'Mint created',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/AdminMintResponse' }
}
}
},
200: {
description: 'Mint already exists',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/AdminMintResponse' }
}
}
},
401: { $ref: '#/components/responses/Unauthorized' },
403: { $ref: '#/components/responses/Forbidden' }
}
}
},
'/admin/mints/{mint_id}/urls': {
post: {
tags: ['Admin'],
summary: 'Add URL to mint',
description: 'Attach an additional URL (clearnet, Tor, mirror) to an existing mint.',
operationId: 'adminAddMintUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['url'],
properties: {
url: { type: 'string', format: 'uri' },
type: { type: 'string', enum: ['clearnet', 'tor', 'mirror'] },
active: { type: 'boolean', default: true }
}
}
}
}
},
responses: {
201: { description: 'URL added' },
404: { $ref: '#/components/responses/NotFound' },
409: { description: 'URL already attached to another mint' }
}
}
},
'/admin/mints/merge': {
post: {
tags: ['Admin'],
summary: 'Merge two mints',
description: 'Merge two mints that represent the same operator. All data is reassigned to target.',
operationId: 'adminMergeMints',
security: [{ AdminApiKey: [] }],
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['source_mint_id', 'target_mint_id'],
properties: {
source_mint_id: { type: 'string', format: 'uuid' },
target_mint_id: { type: 'string', format: 'uuid' },
reason: { type: 'string' }
}
}
}
}
},
responses: {
200: {
description: 'Mints merged',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MergeResponse' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/split': {
post: {
tags: ['Admin'],
summary: 'Undo a merge',
description: 'Revert a previous mint merge operation.',
operationId: 'adminSplitMints',
security: [{ AdminApiKey: [] }],
requestBody: {
required: true,
content: {
'application/json': {
schema: {
type: 'object',
required: ['merge_id'],
properties: {
merge_id: { type: 'string', format: 'uuid' }
}
}
}
}
},
responses: {
200: { description: 'Merge reverted' },
404: { description: 'Merge not found' },
409: { description: 'Merge already reverted' }
}
}
},
'/admin/mints/{mint_id}/disable': {
post: {
tags: ['Admin'],
summary: 'Disable mint',
description: 'Hide a mint from public listings. Mint continues to be probed.',
operationId: 'adminDisableMint',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
requestBody: {
content: {
'application/json': {
schema: {
type: 'object',
properties: {
reason: { type: 'string' }
}
}
}
}
},
responses: {
200: { description: 'Mint disabled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/{mint_id}/enable': {
post: {
tags: ['Admin'],
summary: 'Enable mint',
description: 'Re-enable a previously hidden mint.',
operationId: 'adminEnableMint',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
responses: {
200: { description: 'Mint enabled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/{mint_id}/metadata/refresh': {
post: {
tags: ['Admin'],
summary: 'Force metadata refresh',
description: 'Force metadata fetch, bypassing the hourly limit.',
operationId: 'adminForceMetadata',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
responses: {
200: { description: 'Metadata refresh scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/{mint_id}/trust/recompute': {
post: {
tags: ['Admin'],
summary: 'Force trust recompute',
description: 'Force trust score recomputation using current data.',
operationId: 'adminForceTrust',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
responses: {
200: { description: 'Trust recomputation scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/{mint_id}/status/reset': {
post: {
tags: ['Admin'],
summary: 'Reset mint status',
description: 'Clear stuck mint state. Resets consecutive failures and schedules probe.',
operationId: 'adminResetStatus',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
responses: {
200: { description: 'Status reset, probe scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/jobs': {
get: {
tags: ['Admin'],
summary: 'Inspect job queue',
description: 'View background job queue status.',
operationId: 'adminGetJobs',
security: [{ AdminApiKey: [] }],
parameters: [
{ name: 'status', in: 'query', schema: { type: 'string', enum: ['pending', 'running', 'completed', 'failed'] } },
{ name: 'type', in: 'query', schema: { type: 'string' } },
{ name: 'limit', in: 'query', schema: { type: 'integer', default: 100 } },
{ name: 'offset', in: 'query', schema: { type: 'integer', default: 0 } }
],
responses: {
200: {
description: 'Job list',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/JobListResponse' }
}
}
}
}
}
},
'/admin/system/metrics': {
get: {
tags: ['Admin'],
summary: 'System metrics',
description: 'High-level system health and metrics.',
operationId: 'adminGetMetrics',
security: [{ AdminApiKey: [] }],
responses: {
200: {
description: 'System metrics',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/SystemMetrics' }
}
}
}
}
}
},
'/admin/audit': {
get: {
tags: ['Admin'],
summary: 'Audit log',
description: 'View admin action audit log.',
operationId: 'adminGetAudit',
security: [{ AdminApiKey: [] }],
parameters: [
{ name: 'action', in: 'query', schema: { type: 'string' } },
{ name: 'target_type', in: 'query', schema: { type: 'string' } },
{ name: 'admin_id', in: 'query', schema: { type: 'string' } },
{ name: 'mint_id', in: 'query', description: 'Filter by mint ID', schema: { type: 'string', format: 'uuid' } },
{ name: 'limit', in: 'query', schema: { type: 'integer', default: 100 } },
{ name: 'offset', in: 'query', schema: { type: 'integer', default: 0 } }
],
responses: {
200: {
description: 'Audit log entries',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/AuditLogResponse' }
}
}
}
}
}
},
'/admin/mints/{mint_id}/probe': {
post: {
tags: ['Admin'],
summary: 'Force probe',
description: 'Force an immediate probe of a mint.',
operationId: 'adminForceProbeMint',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
responses: {
200: { description: 'Probe scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/{mint_id}/visibility': {
get: {
tags: ['Admin'],
summary: 'Get mint visibility',
description: 'Get the current visibility status of a mint.',
operationId: 'adminGetMintVisibility',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintId' }],
responses: {
200: {
description: 'Visibility status',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintVisibility' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/by-url/disable': {
post: {
tags: ['Admin'],
summary: 'Disable mint by URL',
description: 'Hide a mint from public listings by URL.',
operationId: 'adminDisableMintByUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintUrl' }],
requestBody: {
content: {
'application/json': {
schema: {
type: 'object',
properties: { reason: { type: 'string' } }
}
}
}
},
responses: {
200: { description: 'Mint disabled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/by-url/enable': {
post: {
tags: ['Admin'],
summary: 'Enable mint by URL',
description: 'Re-enable a hidden mint by URL.',
operationId: 'adminEnableMintByUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintUrl' }],
responses: {
200: { description: 'Mint enabled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/by-url/metadata/refresh': {
post: {
tags: ['Admin'],
summary: 'Force metadata refresh by URL',
description: 'Force metadata fetch by URL, bypassing the hourly limit.',
operationId: 'adminForceMetadataByUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintUrl' }],
responses: {
200: { description: 'Metadata refresh scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/by-url/trust/recompute': {
post: {
tags: ['Admin'],
summary: 'Force trust recompute by URL',
description: 'Force trust score recomputation by URL.',
operationId: 'adminForceTrustByUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintUrl' }],
responses: {
200: { description: 'Trust recomputation scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/by-url/status/reset': {
post: {
tags: ['Admin'],
summary: 'Reset mint status by URL',
description: 'Clear stuck mint state by URL.',
operationId: 'adminResetStatusByUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintUrl' }],
responses: {
200: { description: 'Status reset, probe scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/by-url/probe': {
post: {
tags: ['Admin'],
summary: 'Force probe by URL',
description: 'Force an immediate probe by URL.',
operationId: 'adminForceProbeByUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintUrl' }],
responses: {
200: { description: 'Probe scheduled' },
404: { $ref: '#/components/responses/NotFound' }
}
}
},
'/admin/mints/by-url/visibility': {
get: {
tags: ['Admin'],
summary: 'Get mint visibility by URL',
description: 'Get visibility status by URL.',
operationId: 'adminGetMintVisibilityByUrl',
security: [{ AdminApiKey: [] }],
parameters: [{ $ref: '#/components/parameters/mintUrl' }],
responses: {
200: {
description: 'Visibility status',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/MintVisibility' }
}
}
},
404: { $ref: '#/components/responses/NotFound' }
}
}
}
},
components: {
securitySchemes: {
AdminApiKey: {
type: 'apiKey',
in: 'header',
name: 'X-Admin-Api-Key',
description: 'Admin API key for protected endpoints'
}
},
parameters: {
mintId: {
name: 'mint_id',
in: 'path',
required: true,
description: 'Unique mint identifier (UUID)',
schema: {
type: 'string',
format: 'uuid'
}
},
mintUrl: {
name: 'url',
in: 'query',
required: true,
description: 'Mint URL (will be normalized)',
schema: {
type: 'string',
format: 'uri'
}
}
},
responses: {
NotFound: {
description: 'Mint not found',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Error' }
}
}
},
RateLimited: {
description: 'Rate limit exceeded',
headers: {
'Retry-After': {
description: 'Seconds until rate limit resets',
schema: { type: 'integer' }
},
'X-RateLimit-Limit': {
description: 'Maximum requests per window',
schema: { type: 'integer' }
},
'X-RateLimit-Remaining': {
description: 'Remaining requests in window',
schema: { type: 'integer' }
}
},
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Error' }
}
}
},
Unauthorized: {
description: 'Missing authentication',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Error' }
}
}
},
Forbidden: {
description: 'Invalid authentication',
content: {
'application/json': {
schema: { $ref: '#/components/schemas/Error' }
}
}
}
},
schemas: {
Error: {
type: 'object',
properties: {
error: { type: 'string', description: 'Error message' }
},
required: ['error']
},
HealthResponse: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['healthy', 'unhealthy']
},
database: {
type: 'string',
enum: ['connected', 'disconnected']
},
timestamp: {
type: 'string',
format: 'date-time'
},
version: { type: 'string' }
}
},
StatsResponse: {
type: 'object',
properties: {
mints: {
type: 'object',
properties: {
total: { type: 'integer' },
by_status: {
type: 'object',
additionalProperties: { type: 'integer' }
}
}
},
activity: {
type: 'object',
properties: {
probes_24h: { type: 'integer' },
reviews_total: { type: 'integer' },
incidents_7d: { type: 'integer' }
}
},
computed_at: { type: 'string', format: 'date-time' }
}
},
Mint: {
type: 'object',
properties: {
mint_id: {
type: 'string',
format: 'uuid',
description: 'Unique mint identifier'
},
canonical_url: {
type: 'string',
format: 'uri',
description: 'Primary mint URL'
},
urls: {
type: 'array',
items: { type: 'string', format: 'uri' },
description: 'All known URLs for this mint'
},
name: {
type: 'string',
nullable: true,
description: 'Mint name from metadata'
},
icon_url: {
type: 'string',
format: 'uri',
nullable: true,
description: 'Mint icon URL'
},
status: {
type: 'string',
enum: ['unknown', 'online', 'degraded', 'offline', 'abandoned'],
description: 'Current mint status'
},
offline_since: {
type: 'string',
format: 'date-time',
nullable: true,
description: 'When the mint went offline'
},
last_success_at: {
type: 'string',
format: 'date-time',
nullable: true,
description: 'Last successful probe'
},
last_failure_at: {
type: 'string',
format: 'date-time',
nullable: true,
description: 'Last failed probe'
},
uptime_24h: {
type: 'number',
nullable: true,
description: '24-hour uptime percentage'
},
uptime_7d: {
type: 'number',
nullable: true,
description: '7-day uptime percentage'
},
uptime_30d: {
type: 'number',
nullable: true,
description: '30-day uptime percentage'
},
incidents_7d: {
type: 'integer',
description: 'Incident count in last 7 days'
},
incidents_30d: {
type: 'integer',
description: 'Incident count in last 30 days'
},
trust_score: {
type: 'integer',
nullable: true,
minimum: 0,
maximum: 100,
description: 'Trust score (0-100)'
},
trust_level: {
type: 'string',
enum: ['unknown', 'low', 'medium', 'high', 'excellent'],
nullable: true,
description: 'Trust level category'
}
}
},
MintListResponse: {
type: 'object',
properties: {
mints: {
type: 'array',
items: { $ref: '#/components/schemas/Mint' }
},
total: { type: 'integer' },
limit: { type: 'integer' },
offset: { type: 'integer' }
}
},
MintSubmission: {
type: 'object',
required: ['mint_url'],
properties: {
mint_url: {
type: 'string',
format: 'uri',
description: 'URL of the Cashu mint to submit'
}
}
},
MintSubmissionResponse: {
type: 'object',
properties: {
success: { type: 'boolean' },
mint_id: { type: 'string', format: 'uuid' },
status: { type: 'string' },
message: { type: 'string' }
}
},
MintUrlsResponse: {
type: 'object',
properties: {
canonical_url: { type: 'string', format: 'uri' },
urls: {
type: 'array',
items: {
type: 'object',
properties: {
url: { type: 'string', format: 'uri' },
type: {
type: 'string',
enum: ['clearnet', 'tor', 'mirror']
},
active: { type: 'boolean' },
discovered_at: { type: 'string', format: 'date-time' },
last_seen_at: { type: 'string', format: 'date-time' }
}
}
}
}
},
MintStatus: {
type: 'object',
properties: {
status: {
type: 'string',
enum: ['unknown', 'online', 'degraded', 'offline', 'abandoned']
},
offline_since: {
type: 'string',
format: 'date-time',
nullable: true
},
last_checked_at: {
type: 'string',
format: 'date-time',
nullable: true
},
current_rtt_ms: {
type: 'integer',
nullable: true,
description: 'Current response time in milliseconds'
}
}
},
MintMetadata: {
type: 'object',
description: 'NUT-06 compliant mint metadata',
properties: {
name: { type: 'string', nullable: true },
pubkey: {
type: 'string',
nullable: true,
description: 'Mint public key (hex)'
},
version: { type: 'string', nullable: true },
description: { type: 'string', nullable: true },
description_long: { type: 'string', nullable: true },
contact: {
type: 'object',
nullable: true,
additionalProperties: { type: 'string' }
},
motd: {
type: 'string',
nullable: true,
description: 'Message of the day'
},
icon_url: { type: 'string', format: 'uri', nullable: true },
urls: {
type: 'array',
nullable: true,
items: { type: 'string', format: 'uri' }
},
tos_url: {
type: 'string',
format: 'uri',
nullable: true,
description: 'Terms of service URL'
},
nuts: {
type: 'object',
nullable: true,
description: 'Supported NUTs configuration',
additionalProperties: { type: 'object' }
},
server_time: {
type: 'string',
format: 'date-time',
nullable: true
},
last_fetched_at: { type: 'string', format: 'date-time' }
}
},
MetadataHistoryResponse: {
type: 'object',
properties: {
history: {
type: 'array',
items: {
type: 'object',
properties: {
fetched_at: { type: 'string', format: 'date-time' },
change_type: {
type: 'string',
enum: ['initial', 'update', 'error']
},
diff: {
type: 'object',
nullable: true,
description: 'JSON diff of changes'
},
version: { type: 'string', nullable: true }
}
}
}
}
},
UptimeStats: {
type: 'object',
properties: {
uptime_pct: {
type: 'number',
description: 'Uptime percentage'
},
downtime_seconds: {
type: 'integer',
description: 'Total downtime in seconds'
},
avg_rtt_ms: {
type: 'number',
nullable: true,
description: 'Average response time'
},
p95_rtt_ms: {
type: 'number',
nullable: true,
description: '95th percentile response time'
},
total_checks: { type: 'integer' },
ok_checks: { type: 'integer' }
}
},
UptimeTimeseriesResponse: {
type: 'object',
properties: {
data: {
type: 'array',
items: {
type: 'object',
properties: {
timestamp: { type: 'string', format: 'date-time' },
state: {
type: 'string',
enum: ['up', 'down', 'degraded']
},
ok: { type: 'integer' },
total: { type: 'integer' },
rtt_ms: { type: 'integer', nullable: true }
}
}
}
}
},
IncidentsResponse: {
type: 'object',
properties: {
incidents: {
type: 'array',
items: {
type: 'object',
properties: {
started_at: { type: 'string', format: 'date-time' },
resolved_at: {
type: 'string',
format: 'date-time',
nullable: true
},
duration_seconds: { type: 'integer', nullable: true },
severity: {
type: 'string',
enum: ['minor', 'major', 'critical']
}
}
}
}
}
},
TrustScore: {
type: 'object',
properties: {
score_total: {
type: 'integer',
minimum: 0,
maximum: 100,
nullable: true
},
score_level: {
type: 'string',
enum: ['unknown', 'low', 'medium', 'high', 'excellent']
},
breakdown: {
type: 'object',
nullable: true,
description: 'Detailed score breakdown by component',
properties: {
uptime: {
type: 'object',
properties: {
score: { type: 'number' },
max: { type: 'number' },
details: { type: 'object' }
}
},
speed: {
type: 'object',
properties: {
score: { type: 'number' },
max: { type: 'number' },
details: { type: 'object' }
}
},
reviews: {
type: 'object',
properties: {
score: { type: 'number' },
max: { type: 'number' },
details: { type: 'object' }
}
},
identity: {
type: 'object',
properties: {
score: { type: 'number' },
max: { type: 'number' },
details: { type: 'object' }
}
},
penalties: {
type: 'object',
properties: {
score: { type: 'number' },
max: { type: 'number' },
details: { type: 'object' }
}
}
}
},
computed_at: {
type: 'string',
format: 'date-time',
nullable: true
}
}
},
ReviewsResponse: {
type: 'object',
properties: {
reviews: {
type: 'array',
items: {
type: 'object',
properties: {
event_id: {
type: 'string',
description: 'Nostr event ID'
},
pubkey: {
type: 'string',
description: 'Reviewer Nostr pubkey'
},
created_at: { type: 'string', format: 'date-time' },
rating: {
type: 'integer',
minimum: 1,
maximum: 5,
nullable: true
},
content: {
type: 'string',
nullable: true,
description: 'Review text'
}
}
}
}
}
},
ViewStats: {
type: 'object',
properties: {
views_24h: { type: 'integer' },
views_7d: { type: 'integer' },
views_30d: { type: 'integer' },
unique_sessions_30d: { type: 'integer' },
view_velocity: {
type: 'number',
description: 'Average views per day'
}
}
},
MintFeatures: {
type: 'object',
properties: {
supported_nuts: {
type: 'array',
items: { type: 'integer' },
description: 'List of supported NUT numbers'
},
supports_bolt11: {
type: 'boolean',
description: 'Whether Bolt11 Lightning is supported'
},
min_amount: {
type: 'integer',
nullable: true,
description: 'Minimum transaction amount in sats'
},
max_amount: {
type: 'integer',
nullable: true,
description: 'Maximum transaction amount in sats'
},
has_tor_endpoint: {
type: 'boolean',
description: 'Whether a .onion URL is available'
},
has_multiple_urls: {
type: 'boolean',
description: 'Whether multiple URLs are configured'
},
feature_completeness_score: {
type: 'integer',
minimum: 0,
maximum: 100,
description: 'Overall feature completeness (0-100)'
}
}
},
AdminMintResponse: {
type: 'object',
properties: {
mint_id: { type: 'string', format: 'uuid' },
status: { type: 'string' },
message: { type: 'string' },
created: { type: 'boolean' }
}
},
MergeResponse: {
type: 'object',
properties: {
merge_id: { type: 'string', format: 'uuid' },
source_mint_id: { type: 'string', format: 'uuid' },
target_mint_id: { type: 'string', format: 'uuid' },
message: { type: 'string' }
}
},
JobListResponse: {
type: 'object',
properties: {
jobs: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
type: { type: 'string' },
status: { type: 'string', enum: ['pending', 'running', 'completed', 'failed'] },
payload: { type: 'object' },
run_at: { type: 'string', format: 'date-time' },
retries: { type: 'integer' },
error_message: { type: 'string', nullable: true }
}
}
},
total: { type: 'integer' },
limit: { type: 'integer' },
offset: { type: 'integer' }
}
},
SystemMetrics: {
type: 'object',
properties: {
total_mints: { type: 'integer' },
online_mints: { type: 'integer' },
degraded_mints: { type: 'integer' },
offline_mints: { type: 'integer' },
abandoned_mints: { type: 'integer' },
unknown_mints: { type: 'integer' },
probes_last_minute: { type: 'integer' },
failed_probes_last_minute: { type: 'integer' },
job_backlog: { type: 'integer' },
oldest_job_age_seconds: { type: 'integer' },
worker_heartbeat_seconds: { type: 'integer', nullable: true },
computed_at: { type: 'string', format: 'date-time' }
}
},
AuditLogResponse: {
type: 'object',
properties: {
entries: {
type: 'array',
items: {
type: 'object',
properties: {
id: { type: 'integer' },
admin_id: { type: 'string' },
action: { type: 'string' },
target_type: { type: 'string' },
target_id: { type: 'string', nullable: true },
before_state: { type: 'object', nullable: true },
after_state: { type: 'object', nullable: true },
notes: { type: 'string', nullable: true },
ip_address: { type: 'string', nullable: true },
created_at: { type: 'string', format: 'date-time' }
}
}
},
total: { type: 'integer' },
limit: { type: 'integer' },
offset: { type: 'integer' }
}
},
GlobalReviewsResponse: {
type: 'object',
properties: {
reviews: {
type: 'array',
items: {
type: 'object',
properties: {
event_id: { type: 'string' },
mint_id: { type: 'string', format: 'uuid', nullable: true },
mint_name: { type: 'string', nullable: true },
mint_url: { type: 'string', nullable: true },
pubkey: { type: 'string' },
created_at: { type: 'string', format: 'date-time' },
rating: { type: 'integer', minimum: 1, maximum: 5, nullable: true },
content: { type: 'string', nullable: true }
}
}
},
total: { type: 'integer' },
limit: { type: 'integer' },
offset: { type: 'integer' }
}
},
TrendingMintsResponse: {
type: 'object',
properties: {
window: { type: 'string', enum: ['24h', '7d'] },
mints: {
type: 'array',
items: {
type: 'object',
properties: {
mint_id: { type: 'string', format: 'uuid' },
canonical_url: { type: 'string' },
name: { type: 'string', nullable: true },
icon_url: { type: 'string', nullable: true },
status: { type: 'string' },
trust_score: { type: 'integer', nullable: true },
trust_level: { type: 'string', nullable: true },
view_count: { type: 'integer' },
view_velocity: { type: 'number' },
unique_sessions: { type: 'integer' }
}
}
}
}
},
UptimeAnalytics: {
type: 'object',
properties: {
window: { type: 'string' },
overall: {
type: 'object',
properties: {
total_probes: { type: 'integer' },
successful_probes: { type: 'integer' },
uptime_percent: { type: 'number', nullable: true },
avg_rtt_ms: { type: 'number', nullable: true },
min_rtt_ms: { type: 'number', nullable: true },
max_rtt_ms: { type: 'number', nullable: true }
}
},
by_status: {
type: 'object',
additionalProperties: {
type: 'object',
properties: {
mint_count: { type: 'integer' },
probe_count: { type: 'integer' },
successful_probes: { type: 'integer' }
}
}
},
rtt_distribution: {
type: 'object',
properties: {
fast: { type: 'integer', description: '< 500ms' },
normal: { type: 'integer', description: '500-1000ms' },
slow: { type: 'integer', description: '1000-2000ms' },
degraded: { type: 'integer', description: '> 2000ms' }
}
},
computed_at: { type: 'string', format: 'date-time' }
}
},
VersionAnalytics: {
type: 'object',
properties: {
versions: {
type: 'array',
items: {
type: 'object',
properties: {
version: { type: 'string' },
count: { type: 'integer' },
mints: { type: 'array', items: { type: 'string' } }
}
}
},
total_with_version: { type: 'integer' },
total_mints: { type: 'integer' },
coverage_percent: { type: 'integer' },
computed_at: { type: 'string', format: 'date-time' }
}
},
NutsAnalytics: {
type: 'object',
properties: {
nuts: {
type: 'array',
items: {
type: 'object',
properties: {
nut: { type: 'integer' },
count: { type: 'integer' },
percent: { type: 'integer' }
}
}
},
key_nuts: {
type: 'object',
additionalProperties: { type: 'integer' }
},
total_mints_analyzed: { type: 'integer' },
computed_at: { type: 'string', format: 'date-time' }
}
},
MintVisibility: {
type: 'object',
properties: {
mint_id: { type: 'string', format: 'uuid' },
canonical_url: { type: 'string' },
visibility: { type: 'string', enum: ['public', 'hidden'] },
status: { type: 'string' }
}
}
}
}
};