- Updated branding from "SolaceScanScout" to "Solace" across various files including deployment scripts, API responses, and documentation. - Changed default base URL for Playwright tests and updated security headers to reflect the new branding. - Enhanced README and API documentation to include new authentication endpoints and product access details. This refactor aligns the project branding and improves clarity in the API documentation.
1476 lines
38 KiB
YAML
1476 lines
38 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: SolaceScan API
|
|
description: |
|
|
SolaceScan public explorer API for Chain 138 with tiered access control.
|
|
|
|
## Authentication
|
|
|
|
Track 1 endpoints are public and require no authentication.
|
|
Track 2-4 endpoints require JWT authentication via wallet signature.
|
|
|
|
## Rate Limiting
|
|
|
|
- Track 1: 100 requests/minute per IP
|
|
- Track 2-4: Based on user tier and subscription
|
|
|
|
version: 1.0.0
|
|
contact:
|
|
name: API Support
|
|
email: support@d-bis.org
|
|
license:
|
|
name: MIT
|
|
url: https://opensource.org/licenses/MIT
|
|
|
|
servers:
|
|
- url: https://api.d-bis.org
|
|
description: Production server
|
|
- url: http://localhost:8080
|
|
description: Development server
|
|
|
|
tags:
|
|
- name: Health
|
|
description: Health check endpoints
|
|
- name: Auth
|
|
description: Wallet and user-session authentication endpoints
|
|
- name: Access
|
|
description: RPC product catalog, subscriptions, and API key lifecycle
|
|
- name: Blocks
|
|
description: Block-related endpoints
|
|
- name: Transactions
|
|
description: Transaction-related endpoints
|
|
- name: Addresses
|
|
description: Address-related endpoints
|
|
- name: Search
|
|
description: Unified search endpoints
|
|
- name: Track1
|
|
description: Public RPC gateway endpoints (no auth required)
|
|
- name: MissionControl
|
|
description: Public mission-control health, bridge trace, and cached liquidity helpers
|
|
- name: Track2
|
|
description: Indexed explorer endpoints (auth required)
|
|
- name: Track3
|
|
description: Analytics endpoints (Track 3+ required)
|
|
- name: Track4
|
|
description: Operator endpoints (Track 4 + IP whitelist)
|
|
|
|
paths:
|
|
/health:
|
|
get:
|
|
tags:
|
|
- Health
|
|
summary: Health check
|
|
description: Returns the health status of the API
|
|
operationId: getHealth
|
|
responses:
|
|
'200':
|
|
description: Service is healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
example: ok
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
database:
|
|
type: string
|
|
example: connected
|
|
|
|
/api/v1/auth/nonce:
|
|
post:
|
|
tags:
|
|
- Auth
|
|
summary: Generate wallet auth nonce
|
|
description: Creates a nonce challenge for wallet-signature authentication.
|
|
operationId: createWalletAuthNonce
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/WalletNonceRequest'
|
|
responses:
|
|
'200':
|
|
description: Nonce generated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/WalletNonceResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'503':
|
|
description: Wallet auth storage or database not available
|
|
|
|
/api/v1/auth/wallet:
|
|
post:
|
|
tags:
|
|
- Auth
|
|
summary: Authenticate with wallet signature
|
|
description: Exchanges an address, signature, and nonce for a JWT used by wallet-authenticated track endpoints.
|
|
operationId: authenticateWallet
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/WalletAuthRequest'
|
|
responses:
|
|
'200':
|
|
description: Wallet authenticated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/WalletAuthResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Wallet auth storage or database not available
|
|
|
|
/api/v1/auth/register:
|
|
post:
|
|
tags:
|
|
- Auth
|
|
summary: Register an explorer access user
|
|
description: "Creates an email/password account for the `/access` console and returns a user session token."
|
|
operationId: registerAccessUser
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserRegisterRequest'
|
|
responses:
|
|
'200':
|
|
description: User created and session issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserSessionResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/auth/login:
|
|
post:
|
|
tags:
|
|
- Auth
|
|
summary: Log in to the explorer access console
|
|
description: "Authenticates an email/password user and returns a user session token for `/api/v1/access/*` endpoints."
|
|
operationId: loginAccessUser
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserLoginRequest'
|
|
responses:
|
|
'200':
|
|
description: Session issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/UserSessionResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/me:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: Get current access-console user
|
|
description: Returns the signed-in user profile and any known product subscriptions.
|
|
operationId: getAccessMe
|
|
security:
|
|
- userSessionAuth: []
|
|
responses:
|
|
'200':
|
|
description: Current user and subscriptions
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessMeResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/products:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: List available RPC access products
|
|
description: Returns the commercial and operational RPC products currently modeled by the explorer access layer.
|
|
operationId: listAccessProducts
|
|
responses:
|
|
'200':
|
|
description: Product catalog
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessProductsResponse'
|
|
|
|
/api/v1/access/subscriptions:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: List subscriptions for the signed-in user
|
|
operationId: listAccessSubscriptions
|
|
security:
|
|
- userSessionAuth: []
|
|
responses:
|
|
'200':
|
|
description: Subscription list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessSubscriptionsResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/admin/subscriptions:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: List subscriptions for admin review
|
|
description: Returns pending or filtered subscriptions for users whose email is allowlisted in `ACCESS_ADMIN_EMAILS`.
|
|
operationId: listAccessAdminSubscriptions
|
|
security:
|
|
- userSessionAuth: []
|
|
parameters:
|
|
- name: status
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
enum: [pending, active, suspended, revoked]
|
|
responses:
|
|
'200':
|
|
description: Subscription list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessSubscriptionsResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
description: Admin privileges required
|
|
'503':
|
|
description: Database not available
|
|
post:
|
|
tags:
|
|
- Access
|
|
summary: Approve, suspend, or revoke a subscription
|
|
operationId: updateAccessAdminSubscription
|
|
security:
|
|
- userSessionAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AdminSubscriptionActionRequest'
|
|
responses:
|
|
'200':
|
|
description: Subscription updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessSubscriptionResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
description: Admin privileges required
|
|
'503':
|
|
description: Database not available
|
|
post:
|
|
tags:
|
|
- Access
|
|
summary: Request or activate product access
|
|
description: |
|
|
Creates or updates a product subscription. Self-service products become `active` immediately.
|
|
Approval-gated products such as Core RPC are created in `pending` state.
|
|
operationId: createAccessSubscription
|
|
security:
|
|
- userSessionAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateSubscriptionRequest'
|
|
responses:
|
|
'200':
|
|
description: Subscription saved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessSubscriptionResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/api-keys:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: List API keys for the signed-in user
|
|
operationId: listAccessApiKeys
|
|
security:
|
|
- userSessionAuth: []
|
|
responses:
|
|
'200':
|
|
description: API key records
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessAPIKeysResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
post:
|
|
tags:
|
|
- Access
|
|
summary: Create an API key
|
|
description: |
|
|
Issues an API key for the chosen tier and product. If the product is approval-gated and not already active
|
|
for the user, this endpoint returns `subscription_required`.
|
|
operationId: createAccessApiKey
|
|
security:
|
|
- userSessionAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateAPIKeyRequest'
|
|
responses:
|
|
'200':
|
|
description: API key created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/CreateAPIKeyResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
description: Product access is pending approval or inactive
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: subscription_required
|
|
message: Product access is pending approval or inactive
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/api-keys/{id}:
|
|
post:
|
|
tags:
|
|
- Access
|
|
summary: Revoke an API key
|
|
description: "Revokes the identified API key. `DELETE` is also accepted by the handler, but the current frontend uses `POST`."
|
|
operationId: revokeAccessApiKey
|
|
security:
|
|
- userSessionAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: API key revoked
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RevokeAPIKeyResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
delete:
|
|
tags:
|
|
- Access
|
|
summary: Revoke an API key
|
|
description: Alternate HTTP verb for API key revocation.
|
|
operationId: revokeAccessApiKeyDelete
|
|
security:
|
|
- userSessionAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: API key revoked
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/RevokeAPIKeyResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/usage:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: Get usage summary for the signed-in user
|
|
description: Returns aggregated per-product usage derived from issued API keys.
|
|
operationId: getAccessUsage
|
|
security:
|
|
- userSessionAuth: []
|
|
responses:
|
|
'200':
|
|
description: Usage summary
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessUsageResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/audit:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: Get recent API activity for the signed-in user
|
|
description: Returns recent validated API-key usage log rows for the current user.
|
|
operationId: getAccessAudit
|
|
security:
|
|
- userSessionAuth: []
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 200
|
|
default: 20
|
|
responses:
|
|
'200':
|
|
description: Audit entries
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessAuditResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/admin/audit:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: Get recent API activity across users for admin review
|
|
description: Returns recent validated API-key usage log rows for access admins, optionally filtered by product.
|
|
operationId: getAccessAdminAudit
|
|
security:
|
|
- userSessionAuth: []
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 500
|
|
default: 50
|
|
- name: product
|
|
in: query
|
|
required: false
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Audit entries
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/AccessAuditResponse'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/access/internal/validate-key:
|
|
get:
|
|
tags:
|
|
- Access
|
|
summary: Validate an API key for nginx auth_request or similar edge subrequests
|
|
description: >-
|
|
Requires `X-Access-Internal-Secret` and accepts the presented API key in
|
|
`X-API-Key` or `Authorization: Bearer ...`. Returns `200` or `401` and
|
|
emits validation metadata in response headers.
|
|
operationId: validateAccessApiKeyInternalGet
|
|
parameters:
|
|
- name: X-Access-Internal-Secret
|
|
in: header
|
|
required: true
|
|
schema:
|
|
type: string
|
|
- name: X-API-Key
|
|
in: header
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: Authorization
|
|
in: header
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: X-Access-Method
|
|
in: header
|
|
required: false
|
|
schema:
|
|
type: string
|
|
- name: X-Access-Request-Count
|
|
in: header
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
'200':
|
|
description: Key validated
|
|
headers:
|
|
X-Validated-Product:
|
|
schema:
|
|
type: string
|
|
X-Validated-Tier:
|
|
schema:
|
|
type: string
|
|
X-Validated-Scopes:
|
|
schema:
|
|
type: string
|
|
X-Quota-Remaining:
|
|
schema:
|
|
type: string
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
post:
|
|
tags:
|
|
- Access
|
|
summary: Validate an API key for internal edge enforcement
|
|
description: Requires `X-Access-Internal-Secret` and returns validated key metadata while incrementing usage counters.
|
|
operationId: validateAccessApiKeyInternal
|
|
parameters:
|
|
- name: X-Access-Internal-Secret
|
|
in: header
|
|
required: true
|
|
schema:
|
|
type: string
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/InternalValidateAPIKeyRequest'
|
|
responses:
|
|
'200':
|
|
description: Key validated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/InternalValidateAPIKeyResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'503':
|
|
description: Database not available
|
|
|
|
/api/v1/blocks:
|
|
get:
|
|
tags:
|
|
- Blocks
|
|
summary: List blocks
|
|
description: Returns a paginated list of blocks
|
|
operationId: listBlocks
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
description: Number of blocks to return
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 100
|
|
default: 20
|
|
- name: page
|
|
in: query
|
|
description: Page number
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
minimum: 1
|
|
default: 1
|
|
- name: chain_id
|
|
in: query
|
|
description: Chain ID filter
|
|
required: false
|
|
schema:
|
|
type: integer
|
|
default: 138
|
|
responses:
|
|
'200':
|
|
description: List of blocks
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BlockListResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/api/v1/blocks/{chain_id}/{number}:
|
|
get:
|
|
tags:
|
|
- Blocks
|
|
summary: Get block by number
|
|
description: Returns block details by chain ID and block number
|
|
operationId: getBlockByNumber
|
|
parameters:
|
|
- name: chain_id
|
|
in: path
|
|
required: true
|
|
description: Chain ID
|
|
schema:
|
|
type: integer
|
|
example: 138
|
|
- name: number
|
|
in: path
|
|
required: true
|
|
description: Block number
|
|
schema:
|
|
type: integer
|
|
example: 1000
|
|
responses:
|
|
'200':
|
|
description: Block details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Block'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/InternalServerError'
|
|
|
|
/api/v1/transactions:
|
|
get:
|
|
tags:
|
|
- Transactions
|
|
summary: List transactions
|
|
description: Returns a paginated list of transactions
|
|
operationId: listTransactions
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 20
|
|
- name: page
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 1
|
|
- name: chain_id
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 138
|
|
responses:
|
|
'200':
|
|
description: List of transactions
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/TransactionListResponse'
|
|
|
|
/api/v1/search:
|
|
get:
|
|
tags:
|
|
- Search
|
|
summary: Unified search
|
|
description: |
|
|
Searches for blocks, transactions, or addresses.
|
|
Automatically detects the type based on the query format.
|
|
operationId: search
|
|
parameters:
|
|
- name: q
|
|
in: query
|
|
required: true
|
|
description: Search query (block number, address, or transaction hash)
|
|
schema:
|
|
type: string
|
|
example: "0x1234567890abcdef"
|
|
responses:
|
|
'200':
|
|
description: Search results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SearchResponse'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
|
|
/api/v1/track1/blocks/latest:
|
|
get:
|
|
tags:
|
|
- Track1
|
|
summary: Get latest blocks (Public)
|
|
description: Returns the latest blocks via RPC gateway. No authentication required.
|
|
operationId: getLatestBlocks
|
|
parameters:
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 10
|
|
maximum: 50
|
|
responses:
|
|
'200':
|
|
description: Latest blocks
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/BlockListResponse'
|
|
|
|
/api/v1/mission-control/stream:
|
|
get:
|
|
tags:
|
|
- MissionControl
|
|
summary: Mission-control SSE stream
|
|
description: |
|
|
Server-Sent Events stream with the same inner `data` payload as `GET /api/v1/track1/bridge/status`.
|
|
Emits one event immediately, then refreshes every 20 seconds. Configure nginx with `proxy_buffering off`.
|
|
operationId: getMissionControlStream
|
|
responses:
|
|
'200':
|
|
description: SSE stream
|
|
content:
|
|
text/event-stream:
|
|
schema:
|
|
type: string
|
|
|
|
/api/v1/mission-control/liquidity/token/{address}/pools:
|
|
get:
|
|
tags:
|
|
- MissionControl
|
|
summary: Cached liquidity proxy
|
|
description: |
|
|
30-second in-memory cached proxy to the token-aggregation pools endpoint for the configured `CHAIN_ID`.
|
|
operationId: getMissionControlLiquidityPools
|
|
parameters:
|
|
- name: address
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^0x[a-fA-F0-9]{40}$'
|
|
responses:
|
|
'200':
|
|
description: Upstream JSON response
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'503':
|
|
description: "`TOKEN_AGGREGATION_BASE_URL` not configured"
|
|
|
|
/api/v1/mission-control/bridge/trace:
|
|
get:
|
|
tags:
|
|
- MissionControl
|
|
summary: Resolve a transaction through Blockscout and label 138-side contracts
|
|
description: |
|
|
Queries Blockscout using `BLOCKSCOUT_INTERNAL_URL` and labels the `from` and `to` addresses using Chain 138 entries from `SMART_CONTRACTS_MASTER_JSON`.
|
|
operationId: getMissionControlBridgeTrace
|
|
parameters:
|
|
- name: tx
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
pattern: '^0x[a-fA-F0-9]{64}$'
|
|
responses:
|
|
'200':
|
|
description: Labeled bridge trace
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'502':
|
|
description: Blockscout lookup failed
|
|
|
|
/api/v1/track4/operator/run-script:
|
|
post:
|
|
tags:
|
|
- Track4
|
|
summary: Run an allowlisted operator script
|
|
description: |
|
|
Track 4 endpoint. Requires authenticated wallet, IP allowlisting, `OPERATOR_SCRIPTS_ROOT`, and `OPERATOR_SCRIPT_ALLOWLIST`.
|
|
operationId: runOperatorScript
|
|
security:
|
|
- bearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [script]
|
|
properties:
|
|
script:
|
|
type: string
|
|
description: "Path relative to `OPERATOR_SCRIPTS_ROOT`"
|
|
args:
|
|
type: array
|
|
items:
|
|
type: string
|
|
maxItems: 24
|
|
responses:
|
|
'200':
|
|
description: Script execution result
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
'503':
|
|
description: Script root or allowlist not configured
|
|
|
|
/api/v1/track2/search:
|
|
get:
|
|
tags:
|
|
- Track2
|
|
summary: Advanced search (Auth Required)
|
|
description: Advanced search with indexed data. Requires Track 2+ authentication.
|
|
operationId: track2Search
|
|
security:
|
|
- bearerAuth: []
|
|
parameters:
|
|
- name: q
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: Search results
|
|
'401':
|
|
$ref: '#/components/responses/Unauthorized'
|
|
'403':
|
|
$ref: '#/components/responses/Forbidden'
|
|
|
|
components:
|
|
securitySchemes:
|
|
bearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: JWT token obtained from /api/v1/auth/wallet
|
|
userSessionAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: User session token obtained from /api/v1/auth/register or /api/v1/auth/login
|
|
|
|
schemas:
|
|
WalletNonceRequest:
|
|
type: object
|
|
required: [address]
|
|
properties:
|
|
address:
|
|
type: string
|
|
pattern: '^0x[a-fA-F0-9]{40}$'
|
|
|
|
WalletNonceResponse:
|
|
type: object
|
|
properties:
|
|
address:
|
|
type: string
|
|
nonce:
|
|
type: string
|
|
message:
|
|
type: string
|
|
|
|
WalletAuthRequest:
|
|
type: object
|
|
required: [address, signature, nonce]
|
|
properties:
|
|
address:
|
|
type: string
|
|
pattern: '^0x[a-fA-F0-9]{40}$'
|
|
signature:
|
|
type: string
|
|
nonce:
|
|
type: string
|
|
|
|
WalletAuthResponse:
|
|
type: object
|
|
properties:
|
|
token:
|
|
type: string
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
user:
|
|
type: object
|
|
additionalProperties: true
|
|
|
|
User:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
email:
|
|
type: string
|
|
format: email
|
|
username:
|
|
type: string
|
|
is_admin:
|
|
type: boolean
|
|
|
|
UserRegisterRequest:
|
|
type: object
|
|
required: [email, username, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
username:
|
|
type: string
|
|
password:
|
|
type: string
|
|
minLength: 8
|
|
|
|
UserLoginRequest:
|
|
type: object
|
|
required: [email, password]
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
password:
|
|
type: string
|
|
|
|
UserSessionResponse:
|
|
type: object
|
|
properties:
|
|
user:
|
|
$ref: '#/components/schemas/User'
|
|
token:
|
|
type: string
|
|
expires_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
AccessProduct:
|
|
type: object
|
|
properties:
|
|
slug:
|
|
type: string
|
|
name:
|
|
type: string
|
|
provider:
|
|
type: string
|
|
vmid:
|
|
type: integer
|
|
http_url:
|
|
type: string
|
|
ws_url:
|
|
type: string
|
|
default_tier:
|
|
type: string
|
|
requires_approval:
|
|
type: boolean
|
|
billing_model:
|
|
type: string
|
|
description:
|
|
type: string
|
|
use_cases:
|
|
type: array
|
|
items:
|
|
type: string
|
|
management_features:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
AccessProductsResponse:
|
|
type: object
|
|
properties:
|
|
products:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AccessProduct'
|
|
note:
|
|
type: string
|
|
|
|
AccessAPIKeyRecord:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
name:
|
|
type: string
|
|
tier:
|
|
type: string
|
|
productSlug:
|
|
type: string
|
|
scopes:
|
|
type: array
|
|
items:
|
|
type: string
|
|
monthlyQuota:
|
|
type: integer
|
|
requestsUsed:
|
|
type: integer
|
|
approved:
|
|
type: boolean
|
|
approvedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
rateLimitPerSecond:
|
|
type: integer
|
|
rateLimitPerMinute:
|
|
type: integer
|
|
lastUsedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
expiresAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
revoked:
|
|
type: boolean
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
AccessSubscription:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
productSlug:
|
|
type: string
|
|
tier:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [active, pending, suspended, revoked]
|
|
monthlyQuota:
|
|
type: integer
|
|
requestsUsed:
|
|
type: integer
|
|
requiresApproval:
|
|
type: boolean
|
|
approvedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
approvedBy:
|
|
type: string
|
|
nullable: true
|
|
notes:
|
|
type: string
|
|
nullable: true
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
AccessUsageSummary:
|
|
type: object
|
|
properties:
|
|
product_slug:
|
|
type: string
|
|
active_keys:
|
|
type: integer
|
|
requests_used:
|
|
type: integer
|
|
monthly_quota:
|
|
type: integer
|
|
|
|
AccessMeResponse:
|
|
type: object
|
|
properties:
|
|
user:
|
|
$ref: '#/components/schemas/User'
|
|
subscriptions:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AccessSubscription'
|
|
|
|
AccessSubscriptionsResponse:
|
|
type: object
|
|
properties:
|
|
subscriptions:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AccessSubscription'
|
|
|
|
AccessSubscriptionResponse:
|
|
type: object
|
|
properties:
|
|
subscription:
|
|
$ref: '#/components/schemas/AccessSubscription'
|
|
|
|
AccessAPIKeysResponse:
|
|
type: object
|
|
properties:
|
|
api_keys:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AccessAPIKeyRecord'
|
|
|
|
CreateSubscriptionRequest:
|
|
type: object
|
|
required: [product_slug]
|
|
properties:
|
|
product_slug:
|
|
type: string
|
|
tier:
|
|
type: string
|
|
|
|
CreateAPIKeyRequest:
|
|
type: object
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
tier:
|
|
type: string
|
|
product_slug:
|
|
type: string
|
|
expires_days:
|
|
type: integer
|
|
monthly_quota:
|
|
type: integer
|
|
scopes:
|
|
type: array
|
|
items:
|
|
type: string
|
|
|
|
AdminSubscriptionActionRequest:
|
|
type: object
|
|
required: [subscription_id, status]
|
|
properties:
|
|
subscription_id:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [active, suspended, revoked]
|
|
notes:
|
|
type: string
|
|
|
|
CreateAPIKeyResponse:
|
|
type: object
|
|
properties:
|
|
api_key:
|
|
type: string
|
|
description: Plaintext key is only returned at creation time.
|
|
record:
|
|
$ref: '#/components/schemas/AccessAPIKeyRecord'
|
|
|
|
RevokeAPIKeyResponse:
|
|
type: object
|
|
properties:
|
|
revoked:
|
|
type: boolean
|
|
api_key_id:
|
|
type: string
|
|
|
|
AccessUsageResponse:
|
|
type: object
|
|
properties:
|
|
usage:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AccessUsageSummary'
|
|
|
|
AccessAuditEntry:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
apiKeyId:
|
|
type: string
|
|
keyName:
|
|
type: string
|
|
productSlug:
|
|
type: string
|
|
methodName:
|
|
type: string
|
|
requestCount:
|
|
type: integer
|
|
lastIp:
|
|
type: string
|
|
nullable: true
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
AccessAuditResponse:
|
|
type: object
|
|
properties:
|
|
entries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AccessAuditEntry'
|
|
|
|
InternalValidatedAPIKey:
|
|
type: object
|
|
properties:
|
|
apiKeyId:
|
|
type: string
|
|
userId:
|
|
type: string
|
|
name:
|
|
type: string
|
|
tier:
|
|
type: string
|
|
productSlug:
|
|
type: string
|
|
scopes:
|
|
type: array
|
|
items:
|
|
type: string
|
|
monthlyQuota:
|
|
type: integer
|
|
requestsUsed:
|
|
type: integer
|
|
rateLimitPerSecond:
|
|
type: integer
|
|
rateLimitPerMinute:
|
|
type: integer
|
|
lastUsedAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
expiresAt:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
|
|
InternalValidateAPIKeyRequest:
|
|
type: object
|
|
required: [api_key]
|
|
properties:
|
|
api_key:
|
|
type: string
|
|
method_name:
|
|
type: string
|
|
request_count:
|
|
type: integer
|
|
last_ip:
|
|
type: string
|
|
|
|
InternalValidateAPIKeyResponse:
|
|
type: object
|
|
properties:
|
|
valid:
|
|
type: boolean
|
|
key:
|
|
$ref: '#/components/schemas/InternalValidatedAPIKey'
|
|
|
|
Block:
|
|
type: object
|
|
properties:
|
|
chain_id:
|
|
type: integer
|
|
example: 138
|
|
number:
|
|
type: integer
|
|
example: 1000
|
|
hash:
|
|
type: string
|
|
example: "0x1234567890abcdef"
|
|
parent_hash:
|
|
type: string
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
miner:
|
|
type: string
|
|
transaction_count:
|
|
type: integer
|
|
gas_used:
|
|
type: integer
|
|
gas_limit:
|
|
type: integer
|
|
|
|
Transaction:
|
|
type: object
|
|
properties:
|
|
chain_id:
|
|
type: integer
|
|
hash:
|
|
type: string
|
|
block_number:
|
|
type: integer
|
|
from_address:
|
|
type: string
|
|
to_address:
|
|
type: string
|
|
value:
|
|
type: string
|
|
gas:
|
|
type: integer
|
|
gas_price:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [success, failed]
|
|
|
|
BlockListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Block'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
TransactionListResponse:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Transaction'
|
|
pagination:
|
|
$ref: '#/components/schemas/Pagination'
|
|
|
|
Pagination:
|
|
type: object
|
|
properties:
|
|
page:
|
|
type: integer
|
|
limit:
|
|
type: integer
|
|
total:
|
|
type: integer
|
|
total_pages:
|
|
type: integer
|
|
|
|
SearchResponse:
|
|
type: object
|
|
properties:
|
|
query:
|
|
type: string
|
|
results:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
type:
|
|
type: string
|
|
enum: [block, transaction, address]
|
|
data:
|
|
type: object
|
|
|
|
Error:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
message:
|
|
type: string
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: Bad request
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "bad_request"
|
|
message: "Invalid request parameters"
|
|
|
|
Unauthorized:
|
|
description: Unauthorized - Authentication required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "unauthorized"
|
|
message: "Authentication required"
|
|
|
|
Forbidden:
|
|
description: Forbidden - Insufficient permissions
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "forbidden"
|
|
message: "Insufficient permissions. Track 2+ required."
|
|
|
|
NotFound:
|
|
description: Resource not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "not_found"
|
|
message: "Resource not found"
|
|
|
|
InternalServerError:
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error:
|
|
code: "internal_error"
|
|
message: "An internal error occurred"
|