{
  "openapi": "3.0.3",
  "info": {
    "title": "sondahub OpenAI sandbox",
    "version": "0.10.0",
    "description": "An independent imitation of the OpenAI API for testing, run by sondahub — not affiliated with or endorsed by OpenAI. No model runs here: a scripted model answers, the same request getting the same answer every time.\n\nAuth: Bearer with any key that starts with sk- — sk-sondahub works. Point an SDK at it with base_url https://api.sondahub.com/v1.\n\nPhrases in the user message pick what comes back: [[tokens:N]], [[tool]], [[tools:all]], [[refuse]], [[echo]], [[error:429]] (any status, quota, context), [[flaky:503]] (fails the first try only), [[break]] (a stream that dies halfway), [[slow]].\n\nStored responses and the prompt cache live in the X-Sondahub-Session token each answer carries: send the newest one back as a header and the next request sees them. More at https://sondahub.com/sandboxes/openai/",
    "contact": {
      "name": "sondahub",
      "url": "https://sondahub.com/sandboxes/openai/"
    }
  },
  "externalDocs": {
    "description": "The sandbox, in full",
    "url": "https://sondahub.com/sandboxes/openai/"
  },
  "servers": [
    {
      "url": "https://api.sondahub.com"
    }
  ],
  "security": [
    {
      "openaiKey": []
    }
  ],
  "tags": [
    {
      "name": "Chat",
      "description": "POST /v1/chat/completions: the request checked the way the API checks it, the scripted model’s answer as a ChatCompletion — or chat.completion.chunk events with stream: true."
    },
    {
      "name": "Responses",
      "description": "The Responses API: stored in the session token (store defaults to true), so previous_response_id carries a conversation on and GET finds a response again."
    },
    {
      "name": "Embeddings",
      "description": "Steady, normalised vectors by feature hashing: the same text gives the same vector, and similar texts land close together."
    },
    {
      "name": "Moderations",
      "description": "Nothing is flagged unless the text says [[flag]] or [[flag:category]]."
    },
    {
      "name": "Models",
      "description": "The models the sandbox answers as."
    }
  ],
  "paths": {
    "/v1/chat/completions": {
      "post": {
        "tags": [
          "Chat"
        ],
        "summary": "Create a chat completion",
        "operationId": "CreateChatCompletion",
        "description": "Put [[tokens:N]], [[tool]], [[refuse]], [[echo]], [[error:429]], [[flaky:503]], [[break]] or [[slow]] in the user message to pick what comes back.",
        "responses": {
          "200": {
            "description": "The object.",
            "headers": {
              "x-request-id": {
                "description": "The request id.",
                "schema": {
                  "type": "string"
                }
              },
              "openai-processing-ms": {
                "description": "Time taken.",
                "schema": {
                  "type": "string"
                }
              },
              "x-ratelimit-remaining-tokens": {
                "description": "Simulated quota.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "gpt-5.5, gpt-4o, o3, gpt-4.1-mini… (GET /v1/models lists them). Aliases answer as their dated snapshot.",
                    "example": "gpt-5.5"
                  },
                  "messages": {
                    "type": "array",
                    "description": "system / developer / user / assistant / tool messages; tool calls must be answered by tool messages.",
                    "items": {}
                  },
                  "stream": {
                    "type": "boolean",
                    "description": "Server-sent chat.completion.chunk events, ending in data: [DONE]."
                  },
                  "stream_options": {
                    "type": "object",
                    "description": "include_usage: a last chunk with usage; include_obfuscation (on by default)."
                  },
                  "tools": {
                    "type": "array",
                    "description": "Function (or custom) tools; the model calls one when the message names it, or with [[tool]].",
                    "items": {}
                  },
                  "tool_choice": {
                    "type": "string",
                    "description": "none, auto, required, or {\"type\":\"function\",\"function\":{\"name\":…}}."
                  },
                  "response_format": {
                    "type": "object",
                    "description": "json_schema (an object that fits the schema comes back), json_object, text."
                  },
                  "n": {
                    "type": "integer",
                    "description": "How many choices, 1–128."
                  },
                  "max_completion_tokens": {
                    "type": "integer",
                    "description": "The output limit, reasoning tokens included (max_tokens on older models)."
                  },
                  "reasoning_effort": {
                    "type": "string",
                    "description": "none, minimal, low, medium, high, xhigh: reasoning tokens counted in usage."
                  },
                  "stop": {
                    "type": "array",
                    "description": "Up to 4 stop sequences.",
                    "items": {}
                  },
                  "logprobs": {
                    "type": "boolean",
                    "description": "Log probabilities per token (top_logprobs: up to 20 alternatives)."
                  },
                  "temperature": {
                    "type": "number",
                    "description": "0–2. Reasoning models take only 1."
                  },
                  "prompt_cache_key": {
                    "type": "string",
                    "description": "Groups cached prefixes; prompts of 1,024+ tokens are cached in 128-token steps for the session."
                  }
                },
                "required": [
                  "model",
                  "messages"
                ],
                "example": {
                  "model": "gpt-5.5",
                  "messages": [
                    {
                      "role": "developer",
                      "content": "You are a helpful assistant."
                    },
                    {
                      "role": "user",
                      "content": "Say this is a test"
                    }
                  ]
                }
              },
              "examples": {
                "simple": {
                  "summary": "A message",
                  "value": {
                    "model": "gpt-5.5",
                    "messages": [
                      {
                        "role": "developer",
                        "content": "You are a helpful assistant."
                      },
                      {
                        "role": "user",
                        "content": "Say this is a test"
                      }
                    ]
                  }
                },
                "stream": {
                  "summary": "Streamed, with usage",
                  "value": {
                    "model": "gpt-4o",
                    "stream": true,
                    "stream_options": {
                      "include_usage": true
                    },
                    "messages": [
                      {
                        "role": "user",
                        "content": "[[tokens:120]] Tell me a story."
                      }
                    ]
                  }
                },
                "tools": {
                  "summary": "A tool call",
                  "value": {
                    "model": "gpt-5.5",
                    "messages": [
                      {
                        "role": "user",
                        "content": "What's the weather in Paris?"
                      }
                    ],
                    "tools": [
                      {
                        "type": "function",
                        "function": {
                          "name": "get_weather",
                          "description": "The weather in a city",
                          "parameters": {
                            "type": "object",
                            "properties": {
                              "location": {
                                "type": "string"
                              },
                              "unit": {
                                "type": "string",
                                "enum": [
                                  "celsius",
                                  "fahrenheit"
                                ]
                              }
                            },
                            "required": [
                              "location",
                              "unit"
                            ],
                            "additionalProperties": false
                          },
                          "strict": true
                        }
                      }
                    ]
                  }
                },
                "structured": {
                  "summary": "Structured output",
                  "value": {
                    "model": "gpt-5.5",
                    "messages": [
                      {
                        "role": "user",
                        "content": "Extract the event: Ada and Grace meet on Friday in London."
                      }
                    ],
                    "response_format": {
                      "type": "json_schema",
                      "json_schema": {
                        "name": "event",
                        "strict": true,
                        "schema": {
                          "type": "object",
                          "properties": {
                            "name": {
                              "type": "string"
                            },
                            "date": {
                              "type": "string"
                            },
                            "participants": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            }
                          },
                          "required": [
                            "name",
                            "date",
                            "participants"
                          ],
                          "additionalProperties": false
                        }
                      }
                    }
                  }
                },
                "reasoning": {
                  "summary": "A reasoning model",
                  "value": {
                    "model": "o4-mini",
                    "reasoning_effort": "high",
                    "max_completion_tokens": 4000,
                    "messages": [
                      {
                        "role": "user",
                        "content": "What is (17 * 23) + 4?"
                      }
                    ]
                  }
                },
                "error": {
                  "summary": "A rate-limit error, on purpose",
                  "value": {
                    "model": "gpt-5.5",
                    "messages": [
                      {
                        "role": "user",
                        "content": "[[error:429]] hello"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/responses": {
      "post": {
        "tags": [
          "Responses"
        ],
        "summary": "Create a response",
        "operationId": "CreateResponse",
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          },
          "500": {
            "$ref": "#/components/responses/E500"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "Any chat model, plus the Responses-only ones (o3-pro, gpt-5.5-pro…).",
                    "example": "gpt-5.5"
                  },
                  "input": {
                    "type": "string",
                    "description": "A string, or input items: messages, function_call_output, …"
                  },
                  "instructions": {
                    "type": "string",
                    "description": "A system message for this response (not carried to the next)."
                  },
                  "previous_response_id": {
                    "type": "string",
                    "description": "Continue from a stored response; its function calls must be answered in input."
                  },
                  "tools": {
                    "type": "array",
                    "description": "Function tools, flat: {\"type\":\"function\",\"name\":…,\"parameters\":…}.",
                    "items": {}
                  },
                  "text": {
                    "type": "object",
                    "description": "format: {\"type\":\"json_schema\",\"name\":…,\"schema\":…} for structured output."
                  },
                  "reasoning": {
                    "type": "object",
                    "description": "effort, and summary: auto / concise / detailed for a reasoning summary item."
                  },
                  "stream": {
                    "type": "boolean",
                    "description": "Typed events: response.created … response.output_text.delta … response.completed."
                  },
                  "background": {
                    "type": "boolean",
                    "description": "Answer at once with status queued; GET it until completed (a few seconds)."
                  },
                  "store": {
                    "type": "boolean",
                    "description": "Keep it in the session (default true)."
                  },
                  "max_output_tokens": {
                    "type": "integer",
                    "description": "At least 16; running out makes the response incomplete."
                  },
                  "include": {
                    "type": "array",
                    "description": "reasoning.encrypted_content, message.output_text.logprobs…",
                    "items": {}
                  }
                },
                "required": [
                  "model",
                  "input"
                ],
                "example": {
                  "model": "gpt-5.5",
                  "input": "How do I check if a Python object is an instance of a class?"
                }
              },
              "examples": {
                "simple": {
                  "summary": "Text in, text out",
                  "value": {
                    "model": "gpt-5.5",
                    "instructions": "You are a coding assistant that talks like a pirate.",
                    "input": "How do I check if a Python object is an instance of a class?"
                  }
                },
                "stream": {
                  "summary": "Streamed, with a reasoning summary",
                  "value": {
                    "model": "gpt-5.5",
                    "stream": true,
                    "reasoning": {
                      "effort": "low",
                      "summary": "auto"
                    },
                    "input": "Say streaming works"
                  }
                },
                "tools": {
                  "summary": "A function call",
                  "value": {
                    "model": "gpt-5.5",
                    "input": "What's the weather in Lisbon?",
                    "tools": [
                      {
                        "type": "function",
                        "name": "get_weather",
                        "description": "The weather in a city",
                        "parameters": {
                          "type": "object",
                          "properties": {
                            "city": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "city"
                          ],
                          "additionalProperties": false
                        },
                        "strict": true
                      }
                    ]
                  }
                },
                "background": {
                  "summary": "In the background",
                  "value": {
                    "model": "gpt-5.5",
                    "background": true,
                    "input": "Write a haiku about sandboxes."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/responses/{response_id}": {
      "get": {
        "tags": [
          "Responses"
        ],
        "summary": "Retrieve a response",
        "operationId": "GetResponse",
        "parameters": [
          {
            "name": "response_id",
            "in": "path",
            "required": true,
            "description": "A response id from POST /v1/responses (in this session), or the one every session starts with.",
            "schema": {
              "type": "string"
            },
            "example": "resp_68c1f0a2b3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f607"
          },
          {
            "name": "stream",
            "in": "query",
            "required": false,
            "description": "true: play the stored response back as its event stream.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      },
      "delete": {
        "tags": [
          "Responses"
        ],
        "summary": "Delete a response",
        "operationId": "DeleteResponse",
        "parameters": [
          {
            "name": "response_id",
            "in": "path",
            "required": true,
            "description": "A response id from POST /v1/responses (in this session), or the one every session starts with.",
            "schema": {
              "type": "string"
            },
            "example": "resp_68c1f0a2b3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f607"
          }
        ],
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/responses/{response_id}/cancel": {
      "post": {
        "tags": [
          "Responses"
        ],
        "summary": "Cancel a background response",
        "operationId": "CancelResponse",
        "parameters": [
          {
            "name": "response_id",
            "in": "path",
            "required": true,
            "description": "A response id from POST /v1/responses (in this session), or the one every session starts with.",
            "schema": {
              "type": "string"
            },
            "example": "resp_68c1f0a2b3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f607"
          }
        ],
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/responses/{response_id}/input_items": {
      "get": {
        "tags": [
          "Responses"
        ],
        "summary": "List input items",
        "operationId": "ListInputItems",
        "parameters": [
          {
            "name": "response_id",
            "in": "path",
            "required": true,
            "description": "A response id from POST /v1/responses (in this session), or the one every session starts with.",
            "schema": {
              "type": "string"
            },
            "example": "resp_68c1f0a2b3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f607"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "1–100, default 20.",
            "schema": {
              "type": "integer"
            },
            "example": 20
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "description": "asc or desc (default).",
            "schema": {
              "type": "string"
            },
            "example": "desc"
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "description": "An item id to start after.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    },
    "/v1/responses/input_tokens": {
      "post": {
        "tags": [
          "Responses"
        ],
        "summary": "Count input tokens",
        "operationId": "CountInputTokens",
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "The model.",
                    "example": "gpt-5.5"
                  },
                  "input": {
                    "type": "string",
                    "description": "What to count.",
                    "example": "Hello, world"
                  },
                  "instructions": {
                    "type": "string",
                    "description": "Counted too."
                  },
                  "tools": {
                    "type": "array",
                    "description": "Counted too.",
                    "items": {}
                  }
                },
                "example": {
                  "model": "gpt-5.5",
                  "input": "Hello, world"
                }
              },
              "example": {
                "model": "gpt-5.5",
                "input": "Hello, world"
              }
            }
          }
        }
      }
    },
    "/v1/embeddings": {
      "post": {
        "tags": [
          "Embeddings"
        ],
        "summary": "Create embeddings",
        "operationId": "CreateEmbedding",
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "text-embedding-3-small (1536), text-embedding-3-large (3072) or text-embedding-ada-002.",
                    "example": "text-embedding-3-small"
                  },
                  "input": {
                    "type": "string",
                    "description": "A string or up to 2048 of them (or token arrays).",
                    "example": "The food was delicious and the waiter was friendly."
                  },
                  "dimensions": {
                    "type": "integer",
                    "description": "Fewer dimensions (text-embedding-3 models)."
                  },
                  "encoding_format": {
                    "type": "string",
                    "description": "float (default) or base64 (little-endian float32)."
                  }
                },
                "required": [
                  "model",
                  "input"
                ],
                "example": {
                  "model": "text-embedding-3-small",
                  "input": [
                    "The food was delicious and the waiter was friendly.",
                    "The meal was tasty and the staff were kind."
                  ]
                }
              },
              "example": {
                "model": "text-embedding-3-small",
                "input": [
                  "The food was delicious and the waiter was friendly.",
                  "The meal was tasty and the staff were kind."
                ]
              }
            }
          }
        }
      }
    },
    "/v1/moderations": {
      "post": {
        "tags": [
          "Moderations"
        ],
        "summary": "Classify text",
        "operationId": "CreateModeration",
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "omni-moderation-latest (default) or text-moderation-latest.",
                    "example": "omni-moderation-latest"
                  },
                  "input": {
                    "type": "string",
                    "description": "A string, strings, or text and image_url parts.",
                    "example": "[[flag:violence]] example"
                  }
                },
                "required": [
                  "input"
                ],
                "example": {
                  "model": "omni-moderation-latest",
                  "input": "[[flag:violence]] an example the sandbox flags"
                }
              },
              "example": {
                "model": "omni-moderation-latest",
                "input": "[[flag:violence]] an example the sandbox flags"
              }
            }
          }
        }
      }
    },
    "/v1/models": {
      "get": {
        "tags": [
          "Models"
        ],
        "summary": "List models",
        "operationId": "ListModels",
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          }
        }
      }
    },
    "/v1/models/{model}": {
      "get": {
        "tags": [
          "Models"
        ],
        "summary": "Retrieve a model",
        "operationId": "GetModel",
        "parameters": [
          {
            "name": "model",
            "in": "path",
            "required": true,
            "description": "A model id.",
            "schema": {
              "type": "string"
            },
            "example": "gpt-5.5"
          }
        ],
        "responses": {
          "200": {
            "description": "The object.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "openaiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Any key that starts with sk- — sk-sondahub works."
      }
    },
    "responses": {
      "E400": {
        "description": "{\"error\":{\"message\",\"type\",\"param\",\"code\"}}: what is wrong, in the API’s words.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "param": {
                      "type": "string",
                      "nullable": true
                    },
                    "code": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      },
      "E401": {
        "description": "No key, or one that does not start with sk-.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "param": {
                      "type": "string",
                      "nullable": true
                    },
                    "code": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      },
      "E404": {
        "description": "No such model or response, or a part of the API the sandbox does not model.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "param": {
                      "type": "string",
                      "nullable": true
                    },
                    "code": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      },
      "E429": {
        "description": "Asked for with [[error:429]] or [[error:quota]].",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "param": {
                      "type": "string",
                      "nullable": true
                    },
                    "code": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      },
      "E500": {
        "description": "Asked for with [[error:500]] (or 502, 503, 504).",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string"
                    },
                    "param": {
                      "type": "string",
                      "nullable": true
                    },
                    "code": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}