API · Apps
App catalog endpoints: register, validate, deploy, manifest, status, score, and per-app scoring updates.
All endpoints below are mounted under /v1 on the validator API (https://api.minotaursubnet.com). The CORS allowlist covers https://app.minotaursubnet.com.
GET /v1/apps/
List all App Intents, optionally filtered by deployer address or status.
Query parameters
deployer—strstatus—str
POST /v1/apps/
Create a new App Intent with developer-provided JS and Solidity code.
Request body
body—CreateAppRequest(required) (model CreateAppRequest)name:str=Field(..., description='Human-readable name')description:str=Field('', description='What this app does')supported_chains:list[int]=Field(..., description='Chain IDs (e.g. [1, 8453])')js_code:str=Field(..., description='JS scoring code (required)')solidity_code:str=Field(..., description='Solidity contract code (required)')constructor_args:list[list[str]] | None=Field(None, description='Extra constructor args: [[abi_type, value], ...]')deployer:str=Field('', description='Deployer/owner address (only this address can edit the app). Claimed unless owner_signature proves it.')fee_mode:str=Field('', description="Per-App on-chain fee mode: 'USER' (users pay) or 'APP' (the App's paymaster pays). Empty = operator default (FEE_MODE_DEFAULT).")contract_version:str=Field('', description="Contract base generation: 'v1' (AppIntentBase) or 'v2' (AppIntentBaseV2). Empty = v1.")owner_signature:str=Field('', description="EIP-712 'create_app' signature over the app content (keccak256(js.trim()+'\\u241f'+solidity.trim())). When present, the owner is the RECOVERED signer (proven, not claimed).")owner_deadline:int=Field(0, description='Unix-seconds expiry the owner_signature was signed with.')
GET /v1/apps/manifests
Return manifests for all apps (bulk discovery for miners).
POST /v1/apps/validate
Pre-flight validation for App Intent JS and/or Solidity code.
Request body
body—ValidateAppRequest(required) (model ValidateAppRequest)js_code:str=Field(..., description='JavaScript scoring code to validate')solidity_code:str=Field('', description='Solidity contract code to validate')skip_solidity:bool=Field(False, description='Skip Solidity compilation check')
POST /v1/apps/{app_id}/activate
Admin: promote an app from solving → active (for testing).
Path parameters
app_id—str(required)
Query parameters
chain_id—int
GET /v1/apps/{app_id}/admin-state
Full operator view of an app for the management frontend.
Path parameters
app_id—str(required)
GET /v1/apps/{app_id}/auth-nonce
Next developer-auth nonce to sign for owner-gated actions on this app.
Path parameters
app_id—str(required)
Query parameters
deployer—str
POST /v1/apps/{app_id}/deploy
Deploy an App Intent to a specific chain (or first supported chain).
Path parameters
app_id—str(required)
Query parameters
chain_id—int | Nonewait—boolbody—DeployRequest | None
GET /v1/apps/{app_id}/deploy-quote
Quote the cost to deploy this App (#238): estimated gas per targeted chain
- the deploy fee. Informational — gas is relayer-fronted today and the fee is not yet collected (public deployment is gated off until collection is live).
Path parameters
app_id—str(required)
Query parameters
chain_id—int | None
PATCH /v1/apps/{app_id}/deployments/{chain_id}/config
Apply the relayer-gated on-chain config setters (V2 dex app).
Path parameters
app_id—str(required)chain_id—int(required)
Request body
body—AppConfigRequest(required) (model AppConfigRequest)fee_bps:int | Nonevolume_cap_bps:int | Nonefee_collector:str | None
POST /v1/apps/{app_id}/deployments/{chain_id}/float/deposit
Fund the V2 app-held WETH fee float from the relayer wallet.
Path parameters
app_id—str(required)chain_id—int(required)
Request body
body—FloatDepositRequest(required) (model FloatDepositRequest)amount_wei:int=Field(..., gt=0)wrap:bool=Field(True, description='Wrap relayer ETH into WETH first')
POST /v1/apps/{app_id}/deployments/{chain_id}/float/withdraw
Recover the V2 WETH float (relayer-gated withdrawFloat on-chain) — e.g. before retiring a deployment for a version migration.
Path parameters
app_id—str(required)chain_id—int(required)
Request body
body—FloatWithdrawRequest(required) (model FloatWithdrawRequest)to:str=Field(..., description='Recipient of the recovered WETH')amount_wei:int=Field(..., gt=0)
GET /v1/apps/{app_id}/deployments/{chain_id}/registry-calldata
Prepared AppRegistry registerApp/revokeApp calldata for the current deployment. The revoke needs the registry OWNER key, which stays cold — the frontend surfaces this calldata for external signing.
Path parameters
app_id—str(required)chain_id—int(required)
POST /v1/apps/{app_id}/deployments/{chain_id}/registry/allow-developer
Owner-only AppRegistry.setDeveloperAllowed via the relayer key (which IS the registry owner today). Allowlisting the app’s real developer lets them registerApp/updateManifest from their own wallet — pair with GET …/registry-calldata.
Path parameters
app_id—str(required)chain_id—int(required)
Request body
body—AllowDeveloperRequest(required) (model AllowDeveloperRequest)developer:str=Field(..., description='Developer address to (dis)allow')allowed:bool=Field(True)
POST /v1/apps/{app_id}/deployments/{chain_id}/retire
Mark a chain’s deployment RETIRED — releases the deploy guard so POST /apps/{app_id}/deploy performs an in-place redeploy (the deployment record upserts on (app_id, chain_id)). Store-only: recover any V2 WETH float FIRST via …/float/withdraw.
Path parameters
app_id—str(required)chain_id—int(required)
GET /v1/apps/{app_id}/historical-scenarios
Return PII-stripped historical filled-order scenarios for an app.
Path parameters
app_id—str(required)
Query parameters
n_per_chain—int
POST /v1/apps/{app_id}/link-ss58
Link the app’s EVM deployer to a Bittensor SS58 coldkey (dual-signed).
Path parameters
app_id—str(required)
Request body
body—LinkSS58Request(required) (model LinkSS58Request)ss58:str=Field(..., description="The Bittensor SS58 coldkey to link as the app's payer.")nonce:int=Field(0, description="Deployer's next developer-auth nonce (GET /apps/{id}/auth-nonce).")deadline:int=Field(0, description='Unix-seconds expiry the EVM link_ss58 signature was signed with.')evm_signature:str=Field(..., description='EIP-712 link_ss58 signature from the EVM deployer, binding (app_id, ss58, nonce, deadline).')ss58_signature:str=Field(..., description="Substrate signature by the coldkey over 'MinotaurLinkSS58:{app_id}:{deployer_lower}:{nonce}' (hex).")
GET /v1/apps/{app_id}/manifest
Extract and return the JS manifest for an app.
Path parameters
app_id—str(required)
GET /v1/apps/{app_id}/payer-ss58
The Bittensor coldkey linked to this app’s deployer ("" if unlinked).
Path parameters
app_id—str(required)
POST /v1/apps/{app_id}/registration/approve
ADMIN approves registration: mark approved and register every deployed contract in the AppRegistry (admits it to live routing).
Path parameters
app_id—str(required)
POST /v1/apps/{app_id}/registration/reject
ADMIN rejects the registration request (→ rejected). On-chain state is untouched; the app stays deployed but out of live routing.
Path parameters
app_id—str(required)
Query parameters
body—RejectRegistrationRequest | None
POST /v1/apps/{app_id}/registration/request
Owner submits a DEPLOYED app for registration review (unrequested → requested). Registration is what admits an app to the live order-routing set (on-chain _requireRegistered), so it is gated behind admin approval — this is the request half.
Path parameters
app_id—str(required)
Query parameters
body—RequestRegistrationRequest | None
POST /v1/apps/{app_id}/score
Score an execution plan against an app’s JS scoring function.
Path parameters
app_id—str(required)
Request body
body—ScorePlanRequest(required) (model ScorePlanRequest)plan:dict[str, Any]=Field(..., description='Execution plan to score')params:dict[str, Any]=Field(..., description='Order params → state.raw_params')chain_id:int=Field(0, description='Chain ID (0 = auto-detect from deployment)')intent_function:str=Field('execute', description='Intent function name')fork_block:int | None=Field(None, description='Optional historical block number to rewind the anvil fork to before simulating. Used by miner-side Stage-2 replay of historical filled orders so the plan is evaluated against the pool state at the time of the original order. Requires the upstream RPC to support archive reads.')
PUT /v1/apps/{app_id}/scoring
Update the JS scoring code for an App Intent.
Path parameters
app_id—str(required)
Request body
body—UpdateScoringRequest(required) (model UpdateScoringRequest)new_js_code:str=Field(..., description='New JavaScript scoring source')caller:str=Field('', description='Deprecated, ignored. Authorization is bysignature.')signature:str=Field('', description="EIP-712 developer-auth signature from the app's deployer (required if a deployer was set). Binds action=update_scoring, app_id, keccak(new_js_code), nonce, deadline.")nonce:int=Field(0, description="Deployer's next developer-auth nonce (GET /apps/{id}/auth-nonce). Must equal last_consumed + 1; consumed once on success.")deadline:int=Field(0, description='Unix-seconds expiry the signature was signed with.')
PUT /v1/apps/{app_id}/solidity
Replace the stored contract source so the next deploy compiles it.
Path parameters
app_id—str(required)
Request body
body—UpdateSolidityRequest(required) (model UpdateSolidityRequest)solidity_code:str=Field(..., description='New contract source')constructor_args:list[list[str]] | None=Field(None, description='Replacement ctor args: [[abi_type, value], ...]; omit to keep')contract_version:str=Field('', description="New base generation ('v1'/'v2'); omit to keep")
GET /v1/apps/{app_id}/status
Get an App Intent’s status and execution statistics.
Path parameters
app_id—str(required)