{
  "openapi": "3.1.0",
  "info": {
    "title": "SkinsNode API",
    "summary": "CS2 skin fulfillment API",
    "description": "Read live CS2 skin inventory, create customer orders, and track delivery with signed order.updated callbacks.",
    "version": "2026-04-30",
    "contact": {
      "name": "SkinsNode onboarding",
      "url": "https://t.me/tek9nino"
    }
  },
  "servers": [
    {
      "url": "https://api.skinsnode.com",
      "description": "Production API"
    }
  ],
  "security": [
    {
      "clientId": [],
      "clientSecret": []
    }
  ],
  "paths": {
    "/v1/health": {
      "get": {
        "summary": "Check API liveness",
        "security": [],
        "responses": {
          "200": {
            "description": "API is available",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "status": "ok",
                  "service": "skinsnode"
                }
              }
            }
          }
        }
      }
    },
    "/v1/wallet": {
      "get": {
        "summary": "Read wallet balance",
        "responses": {
          "200": {
            "description": "Authenticated client wallet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/catalog": {
      "get": {
        "summary": "List available catalog items",
        "description": "Return items currently available to the authenticated account.",
        "responses": {
          "200": {
            "description": "Available catalog items",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/orders": {
      "post": {
        "summary": "Create an asynchronous order",
        "description": "Accept an order request for asynchronous processing and validate expected price.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrderRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Order accepted for asynchronous processing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateOrderResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          }
        }
      }
    },
    "/v1/orders/{externalId}": {
      "get": {
        "summary": "Read order status",
        "parameters": [
          {
            "name": "externalId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Store order ID used as the SkinsNode idempotency key."
          }
        ],
        "responses": {
          "200": {
            "description": "Latest order state",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "clientId": {
        "type": "apiKey",
        "in": "header",
        "name": "x-client-id"
      },
      "clientSecret": {
        "type": "apiKey",
        "in": "header",
        "name": "x-client-secret"
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, inactive, or invalid client credentials."
      },
      "Forbidden": {
        "description": "Source IP is not allowed for this client."
      },
      "NotFound": {
        "description": "Catalog item or order was not found."
      },
      "ValidationError": {
        "description": "Request body, params, or query failed validation."
      }
    },
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "required": [
          "status",
          "service"
        ],
        "properties": {
          "status": {
            "type": "string",
            "const": "ok"
          },
          "service": {
            "type": "string",
            "const": "skinsnode"
          }
        }
      },
      "WalletResponse": {
        "type": "object",
        "required": [
          "clientId",
          "currency",
          "availableBalance"
        ],
        "properties": {
          "clientId": {
            "type": "string",
            "example": "client_live_abc123"
          },
          "currency": {
            "type": "string",
            "example": "USD"
          },
          "availableBalance": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Integer cents as a string."
          }
        }
      },
      "CatalogResponse": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogItem"
            }
          }
        }
      },
      "CatalogItem": {
        "type": "object",
        "required": [
          "id",
          "marketHashName",
          "price",
          "currency"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "marketHashName": {
            "type": "string"
          },
          "price": {
            "type": "integer",
            "minimum": 0,
            "description": "Integer cents."
          },
          "currency": {
            "type": "string",
            "example": "USD"
          },
          "phase": {
            "type": [
              "string",
              "null"
            ]
          },
          "floatValue": {
            "type": [
              "string",
              "null"
            ]
          },
          "paintIndex": {
            "type": [
              "integer",
              "null"
            ]
          },
          "paintSeed": {
            "type": [
              "integer",
              "null"
            ]
          },
          "rarityColor": {
            "type": [
              "string",
              "null"
            ]
          },
          "classId": {
            "type": [
              "string",
              "null"
            ]
          },
          "instanceId": {
            "type": [
              "string",
              "null"
            ]
          },
          "imageUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      },
      "CreateOrderRequest": {
        "type": "object",
        "required": [
          "catalogItemId",
          "expectedPrice",
          "externalId",
          "webhookUrl",
          "tradeUrl"
        ],
        "properties": {
          "catalogItemId": {
            "type": "string",
            "format": "uuid"
          },
          "expectedPrice": {
            "type": "integer",
            "minimum": 0,
            "description": "Expected item price in integer cents."
          },
          "externalId": {
            "type": "string",
            "description": "Client order ID used as an idempotency key."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri"
          },
          "tradeUrl": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "CreateOrderResponse": {
        "type": "object",
        "required": [
          "externalId",
          "status",
          "acceptedAt"
        ],
        "properties": {
          "externalId": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "const": "accepted"
          },
          "acceptedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "OrderResponse": {
        "type": "object",
        "required": [
          "externalId",
          "status",
          "item",
          "pricing",
          "failure",
          "timestamps"
        ],
        "properties": {
          "externalId": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "steamOfferId": {
            "type": [
              "string",
              "null"
            ]
          },
          "tradeUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "item": {
            "$ref": "#/components/schemas/CatalogItem"
          },
          "pricing": {
            "$ref": "#/components/schemas/Pricing"
          },
          "failure": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Failure"
              },
              {
                "type": "null"
              }
            ]
          },
          "timestamps": {
            "type": "object",
            "additionalProperties": {
              "type": [
                "string",
                "null"
              ],
              "format": "date-time"
            }
          }
        }
      },
      "OrderStatus": {
        "type": "string",
        "enum": [
          "queued",
          "processing",
          "accepted",
          "pending",
          "sent",
          "completed",
          "failed",
          "cancelled",
          "expired",
          "reversed"
        ]
      },
      "Pricing": {
        "type": "object",
        "required": [
          "currency",
          "amount"
        ],
        "properties": {
          "currency": {
            "type": "string",
            "example": "USD"
          },
          "amount": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Integer cents as a string."
          }
        }
      },
      "Failure": {
        "type": "object",
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "item_unavailable",
              "price_changed",
              "insufficient_funds",
              "cancelled"
            ]
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "SkinsNode API docs",
    "url": "https://skinsnode.com/docs"
  }
}
