--- # 0x API Spectral Ruleset # Generated by analysing openapi/0x-api.yaml and openapi/0x-cross-chain.yaml. # These rules encode the dominant patterns observed across the 0x API surface # (Swap, Gasless, Cross-Chain, Trade Analytics, Sources). The rules apply # Spectral 6.x conventions and may be referenced from a `.spectral.yml` # config via `extends:`. formats: - oas3 rules: # --- INFO / METADATA -------------------------------------------------------- 0x-info-title-prefix: description: >- 0x specs are titled "0x API" or "0x API" — match that pattern. message: Info.title MUST start with "0x" severity: error given: $.info.title then: function: pattern functionOptions: match: "^0x( [A-Z][A-Za-z0-9-]+)* API$" 0x-info-description-required: description: Every spec must have an info.description with at least 40 chars. message: Info.description is required (>= 40 chars) severity: warn given: $.info then: field: description function: truthy 0x-info-version-required: description: Spec version MUST be set (e.g. v2 for Swap/Gasless, v1 for Cross-Chain). message: Info.version is required severity: error given: $.info then: field: version function: truthy # --- SERVERS ---------------------------------------------------------------- 0x-server-url-canonical: description: All 0x APIs are served from https://api.0x.org. message: server.url MUST be https://api.0x.org severity: error given: $.servers[*].url then: function: pattern functionOptions: match: "^https://api\\.0x\\.org$" # --- PATHS — NAMING CONVENTIONS -------------------------------------------- 0x-paths-kebab-case: description: >- Path segments use kebab-case (allowance-holder, trade-analytics, gasless-approval-tokens, tx-history-beta). Reject snake_case and camelCase. message: Path segments MUST be kebab-case severity: warn given: $.paths.*~ then: function: pattern functionOptions: match: "^(/[a-z0-9-]+|/\\{[A-Za-z]+\\})+$" 0x-paths-no-trailing-slash: description: Paths must not end with a trailing slash. message: Path MUST NOT end with '/' severity: error given: $.paths.*~ then: function: pattern functionOptions: notMatch: "/$" # --- OPERATIONS ------------------------------------------------------------- 0x-operation-operationid-required: description: Every operation MUST declare an operationId (used by SDK generators). message: operationId is required severity: error given: $.paths.*[get,post,put,delete,patch] then: field: operationId function: truthy 0x-operation-operationid-namespaced: description: >- 0x operationIds follow `::::` (e.g. swap::permit2::getQuote, gasless::submit, crossChain::getQuotes). Enforce double-colon namespacing or camelCase verb names. message: operationId SHOULD be namespaced (e.g. swap::permit2::getQuote) or camelCase severity: warn given: $.paths.*[get,post,put,delete,patch].operationId then: function: pattern functionOptions: match: "^([a-z][A-Za-z0-9]*)(::[a-z][A-Za-z0-9]*)*$" 0x-operation-summary-required: description: Every operation MUST have a Title Case summary. message: Operation summary is required (Title Case) severity: error given: $.paths.*[get,post,put,delete,patch] then: field: summary function: truthy 0x-operation-description-required: description: Operation description is required and should be at least 30 chars. message: Operation description is required severity: warn given: $.paths.*[get,post,put,delete,patch] then: field: description function: truthy 0x-operation-tags-required: description: >- Every operation MUST be tagged with one of: Swap, Gasless, Cross-Chain, Trade Analytics, Sources. message: Operation MUST have at least one tag severity: error given: $.paths.*[get,post,put,delete,patch].tags then: function: length functionOptions: min: 1 0x-operation-microcks-extension: description: >- Operations SHOULD include x-microcks-operation with dispatcher FALLBACK for replayable mock generation. message: x-microcks-operation extension recommended severity: info given: $.paths.*[get,post,put,delete,patch] then: field: x-microcks-operation function: truthy # --- TAGS ------------------------------------------------------------------- 0x-tags-title-case: description: Tag names use Title Case ("Swap", "Cross-Chain", "Trade Analytics"). message: Tag names MUST be Title Case severity: warn given: $.paths.*[get,post,put,delete,patch].tags[*] then: function: pattern functionOptions: match: "^[A-Z][A-Za-z0-9-]*( [A-Z][A-Za-z0-9-]*)*$" # --- PARAMETERS / HEADERS --------------------------------------------------- 0x-header-api-key-required: description: >- All 0x API operations require the `0x-api-key` header for authentication. message: Every operation MUST require the 0x-api-key header severity: error given: $.paths.*[get,post,put,delete,patch] then: field: parameters function: schema functionOptions: schema: type: array contains: type: object properties: name: { const: "0x-api-key" } in: { const: header } required: { const: true } required: [name, in, required] 0x-header-version-required: description: >- Swap, Gasless, Sources, and Trade Analytics operations require the `0x-version` header (currently `v2`). message: Operation SHOULD require the 0x-version header severity: warn given: $.paths.*[get,post,put,delete,patch] then: field: parameters function: schema functionOptions: schema: type: array contains: type: object properties: name: { const: "0x-version" } in: { const: header } required: [name, in] 0x-parameter-camelcase: description: >- Query and path parameter names use camelCase (chainId, sellToken, buyToken, sellAmount, taker, tradeHash, includedSources, excludedSources, slippageBps). message: Parameter names MUST be camelCase severity: warn given: "$.paths.*[get,post,put,delete,patch].parameters[?(@.in=='query' || @.in=='path')].name" then: function: pattern functionOptions: match: "^[a-z][a-zA-Z0-9]*$" 0x-parameter-description-required: description: All parameters MUST be documented. message: Parameter description is required severity: warn given: $.paths.*[get,post,put,delete,patch].parameters[*] then: field: description function: truthy 0x-chainid-parameter-required: description: >- Almost every 0x endpoint takes a `chainId` query parameter to route the request to the correct EVM chain (or non-EVM virtual chain ID for Solana, HyperCore, Tron in the Cross-Chain API). message: chainId query parameter expected on chain-scoped operations severity: info given: "$.paths.*[get,post,put,delete,patch].parameters[?(@.in=='query')].name" then: function: enumeration functionOptions: values: - chainId - originChainId - destinationChainId # --- RESPONSES -------------------------------------------------------------- 0x-response-200-required: description: Every operation MUST document a 200 response. message: 200 response is required severity: error given: $.paths.*[get,post,put,delete,patch].responses then: field: "200" function: truthy 0x-response-400-recommended: description: >- Most 0x operations return 400 for INPUT_INVALID / validation failures — document it. message: 400 response recommended severity: warn given: $.paths.*[get,post,put,delete,patch].responses then: field: "400" function: truthy 0x-response-json-content-type: description: All responses MUST be application/json. message: Response content type MUST be application/json severity: error given: $.paths.*[get,post,put,delete,patch].responses.*.content then: field: "application/json" function: truthy # --- SCHEMAS — PROPERTY NAMING --------------------------------------------- 0x-schema-camelcase-properties: description: >- Schema properties use camelCase (buyToken, sellAmount, allowanceTarget, blockNumber, gasPrice, totalNetworkFee, liquidityAvailable). message: Schema properties MUST be camelCase severity: warn given: $.components.schemas.*.properties.*~ then: function: pattern functionOptions: match: "^[a-z][a-zA-Z0-9]*$" 0x-evm-address-pattern: description: >- EVM address fields must use the canonical regex `^0x[a-fA-F0-9]{40}$`. message: EVM address fields SHOULD enforce the standard 20-byte hex pattern severity: info given: $..properties[?(@property.match(/Token$|Address$|allowanceTarget|taker|recipient/i))] then: field: pattern function: truthy 0x-numeric-string-pattern: description: >- On-chain integer amounts (buyAmount, sellAmount, gas, value, gasPrice, blockNumber) are returned as decimal strings — enforce string type with a numeric pattern. message: Amount-like fields SHOULD be decimal strings severity: info given: $..properties[?(@property.match(/Amount$|^gas$|^value$|^gasPrice$|^blockNumber$/))] then: field: type function: enumeration functionOptions: values: [string] # --- SECURITY --------------------------------------------------------------- 0x-security-scheme-apikey: description: >- 0x uses an API key passed via the `0x-api-key` request header. The spec SHOULD declare an `apiKey` security scheme. message: "Spec SHOULD declare an `apiKey` security scheme with name '0x-api-key' and `in: header`" severity: warn given: $.components.securitySchemes then: function: truthy # --- HTTP METHOD CONVENTIONS ------------------------------------------------ 0x-get-no-request-body: description: GET operations MUST NOT have a request body. message: GET operations MUST NOT define requestBody severity: error given: $.paths.*.get then: field: requestBody function: falsy 0x-post-has-request-body: description: >- POST operations (e.g. /gasless/submit) SHOULD define a requestBody. message: POST operations SHOULD define a requestBody severity: warn given: $.paths.*.post then: field: requestBody function: truthy