Skip to content

OpenRouter’s open‑source alternative. Multi-model/Multi-API-format/Multi-tenant LLM API aggregation platform.

License

Notifications You must be signed in to change notification settings

cubeofcube-dev/one-api

 
 

Repository files navigation

One API

Synopsis

Open‑source version of OpenRouter, managed through a unified gateway that handles all AI SaaS model calls. Core functions include:

  1. Aggregating chat, image, speech, TTS, embeddings, rerank and other capabilities.
  2. Aggregating multiple model providers such as OpenAI, Anthropic, Azure, Google Vertex, OpenRouter, DeepSeek, Replicate, AWS Bedrock, etc.
  3. Aggregating various upstream API request formats like Chat Completion, Response, Claude Messages.
  4. Supporting different request formats; users can issue requests via Chat Completion, Response, or Claude Messages, which are automatically and transparently converted to the native request format of the upstream model. Even if the client sends a mismatched request format to wrong api endpoint, it will still be correctly processed.
  5. Supporting multi‑tenant management, allowing each tenant to set distinct quotas and permissions.
  6. Supporting generation of sub‑API Keys; each tenant can create multiple sub‑API Keys, each of which can be bound to different models and quotas.

Also welcome to register and use my deployed one-api gateway, which supports various mainstream models. For usage instructions, please refer to https://wiki.laisky.com/projects/gpt/pay/.

Try it at https://oneapi.laisky.com, login with test / 12345678. 🚀

=== One-API Compatibility Matrix 2025-11-28T22:05:53Z ===

Request Format                         gpt-4o-mini  gpt-5-mini                              claude-haiku-4-5  gemini-2.5-flash  openai/gpt-oss-20b  deepseek-chat  grok-4-fast-non-reasoning  azure-gpt-5-nano
Chat (stream=false)                    PASS 8.81s   PASS 11.41s                             PASS 14.27s       PASS 2.96s        PASS 1.74s          PASS 9.25s     PASS 5.25s                 PASS 14.29s
Chat (stream=true)                     PASS 9.44s   PASS 13.27s                             PASS 4.45s        PASS 6.05s        PASS 2.10s          PASS 9.62s     PASS 3.23s                 PASS 10.47s
Chat Tools (stream=false)              PASS 9.74s   PASS 13.85s                             PASS 3.84s        SKIP              PASS 7.01s          SKIP           PASS 10.56s                SKIP
Chat Tools (stream=true)               PASS 13.58s  PASS 9.00s                              PASS 5.12s        PASS 5.34s        PASS 5.57s          PASS 9.61s     PASS 6.12s                 PASS 13.95s
Chat Tools History (stream=false)      PASS 7.37s   PASS 12.49s                             PASS 9.84s        PASS 13.12s       SKIP                PASS 16.89s    PASS 5.01s                 SKIP
Chat Tools History (stream=true)       PASS 4.60s   SKIP                                    PASS 4.14s        PASS 6.80s        PASS 7.81s          PASS 11.95s    PASS 2.57s                 SKIP
Chat Structured (stream=false)         PASS 11.89s  PASS 14.03s                             PASS 12.85s       PASS 6.08s        PASS 5.87s          PASS 37.34s    PASS 4.67s                 PASS 9.83s
Chat Structured (stream=true)          PASS 9.58s   PASS 11.36s                             PASS 4.04s        PASS 3.33s        PASS 9.00s          PASS 28.40s    PASS 6.62s                 PASS 12.56s
Response (stream=false)                PASS 8.74s   PASS 28.93s                             PASS 12.20s       PASS 6.35s        PASS 6.00s          PASS 30.73s    PASS 8.62s                 PASS 14.16s
Response (stream=true)                 PASS 9.53s   PASS 14.59s                             PASS 7.80s        PASS 7.36s        PASS 10.23s         PASS 8.24s     PASS 9.50s                 PASS 15.41s
Response Vision (stream=false)         PASS 9.62s   PASS 14.01s                             PASS 12.02s       PASS 8.84s        SKIP                SKIP           PASS 8.20s                 PASS 13.97s
Response Vision (stream=true)          PASS 8.34s   PASS 8.34s                              PASS 3.70s        PASS 6.76s        SKIP                SKIP           PASS 8.07s                 PASS 13.52s
Response Tools (stream=false)          PASS 11.71s  PASS 8.18s                              PASS 6.16s        PASS 10.37s       PASS 4.78s          PASS 6.71s     PASS 9.13s                 PASS 9.52s
Response Tools (stream=true)           PASS 4.41s   PASS 13.48s                             PASS 11.03s       PASS 4.17s        PASS 2.68s          PASS 19.58s    PASS 10.05s                PASS 5.58s
Response Tools History (stream=false)  PASS 5.62s   PASS 9.07s                              PASS 7.95s        PASS 10.99s       SKIP                PASS 13.50s    PASS 7.01s                 PASS 14.31s
Response Tools History (stream=true)   PASS 6.36s   PASS 13.52s                             PASS 11.05s       PASS 13.25s       PASS 5.65s          PASS 9.96s     PASS 6.15s                 PASS 7.99s
Response Structured (stream=false)     PASS 7.83s   PASS 15.24s                             PASS 3.85s        PASS 8.89s        PASS 8.67s          PASS 13.38s    PASS 5.70s                 PASS 12.46s
Response Structured (stream=true)      PASS 4.98s   PASS 18.41s                             PASS 6.76s        PASS 3.28s        PASS 9.46s          PASS 20.16s    PASS 4.76s                 PASS 13.72s
Claude (stream=false)                  PASS 3.88s   PASS 9.11s                              PASS 9.77s        PASS 3.33s        PASS 4.74s          PASS 6.78s     PASS 3.88s                 PASS 7.76s
Claude (stream=true)                   PASS 6.26s   PASS 9.35s                              PASS 14.09s       PASS 6.76s        PASS 3.67s          PASS 6.44s     PASS 5.83s                 PASS 6.60s
Claude Tools (stream=false)            PASS 14.22s  PASS 12.48s                             PASS 4.99s        PASS 2.75s        PASS 12.08s         PASS 14.25s    PASS 5.87s                 PASS 14.05s
Claude Tools (stream=true)             PASS 6.03s   PASS 8.23s                              PASS 8.53s        SKIP              PASS 4.89s          PASS 7.33s     PASS 4.16s                 PASS 13.13s
Claude Tools History (stream=false)    PASS 8.90s   FAIL response missing tool_use block …  PASS 8.46s        PASS 8.42s        SKIP                PASS 26.26s    PASS 6.21s                 PASS 14.64s
Claude Tools History (stream=true)     PASS 7.96s   SKIP                                    PASS 7.32s        PASS 13.79s       PASS 4.51s          PASS 9.76s     PASS 3.61s                 PASS 19.42s
Claude Structured (stream=false)       PASS 10.04s  SKIP                                    PASS 13.38s       PASS 6.82s        PASS 5.23s          PASS 13.79s    PASS 9.52s                 SKIP
Claude Structured (stream=true)        PASS 5.23s   SKIP                                    PASS 5.72s        PASS 13.11s       PASS 3.80s          PASS 19.28s    PASS 1.82s                 SKIP

Totals  | Requests: 208 | Passed: 188 | Failed: 1 | Skipped: 19

Failures:
- gpt-5-mini - Claude Tools History (stream=false) -> response missing tool_use block or assistant text

Skipped (unsupported combinations):
- azure-gpt-5-nano - Chat Tools (stream=false) -> GPT-5 reasoning model inconsistently returns reasoning instead of tool calls
- azure-gpt-5-nano - Chat Tools History (stream=false) -> Model returns reasoning text instead of tool calls
- azure-gpt-5-nano - Chat Tools History (stream=true) -> Model returns reasoning text instead of tool calls when streaming
- azure-gpt-5-nano - Claude Structured (stream=false) -> Azure GPT-5 nano does not return structured JSON for Claude messages (empty content)
- azure-gpt-5-nano - Claude Structured (stream=true) -> Azure GPT-5 nano does not return structured JSON for Claude messages (empty content)
- deepseek-chat - Chat Tools (stream=false) -> Model times out on non-streaming tool invocation requests
- deepseek-chat - Response Vision (stream=false) -> vision input unsupported by model deepseek-chat
- deepseek-chat - Response Vision (stream=true) -> vision input unsupported by model deepseek-chat
- gemini-2.5-flash - Chat Tools (stream=false) -> Model returns text instead of tool invocations despite forced tool_choice
- gemini-2.5-flash - Claude Tools (stream=true) -> Model returns text instead of tool invocations despite forced tool_choice
- gpt-5-mini - Chat Tools History (stream=true) -> GPT-5 reasoning model inconsistently returns reasoning instead of tool calls when streaming
- gpt-5-mini - Claude Structured (stream=false) -> GPT-5 mini returns empty content for Claude structured requests
- gpt-5-mini - Claude Structured (stream=true) -> GPT-5 mini streams only usage deltas, never emitting structured JSON blocks
- gpt-5-mini - Claude Tools History (stream=true) -> GPT-5 reasoning model inconsistently returns reasoning instead of tool calls
- openai/gpt-oss-20b - Chat Tools History (stream=false) -> Model refuses forced tool_choice (upstream returns 400 tool_use_failed)
- openai/gpt-oss-20b - Claude Tools History (stream=false) -> Model refuses forced tool_choice (upstream returns 400 tool_use_failed)
- openai/gpt-oss-20b - Response Tools History (stream=false) -> Model refuses forced tool_choice (upstream returns 400 tool_use_failed)
- openai/gpt-oss-20b - Response Vision (stream=false) -> vision input unsupported by model openai/gpt-oss-20b
- openai/gpt-oss-20b - Response Vision (stream=true) -> vision input unsupported by model openai/gpt-oss-20b

Why this fork exists

The original author stopped maintaining the project, leaving critical PRs and new features unaddressed. As a long‑time contributor, I’ve forked the repository and rebuilt the core to keep the ecosystem alive and evolving.

Tutorial

Docker Compose Deployment

Docker images available on Docker Hub:

  • ppcelery/one-api:latest
  • ppcelery/one-api:arm64-latest

The initial default account and password are root / 123456. Listening port can be configured via the PORT environment variable, default is 3000.

Run one-api using docker-compose:

All environment variables can be set via the environment section in the docker-compose.yml file, please refer to ./common/config/config.go for all available configuration options.

oneapi:
  image: ppcelery/one-api:latest
  restart: unless-stopped
  logging:
    driver: "json-file"
    options:
      max-size: "10m"
  volumes:
    - /var/lib/oneapi:/data
  ports:
    - 3000:3000

Tip

For production environments, consider using proper secret management solutions instead of hardcoding sensitive values in environment variables.

Kubernetes Deployment

The Kubernetes deployment guide has been moved into a dedicated document:

Contributors

New Features

Universal Features

I18n Support

Support internationalization (i18n) in the web frontend, including English, Chinese, French, Spanish, and Japanese.

Unified Billing System

All channels share a four-layer billing pipeline (channel overrides → adapter defaults → global fallback → safe default) with support for tiered token pricing, cached prompt buckets, and per-second/per-image media meters. Administrators can fetch defaults, override specific models, and audit every call via X-Oneapi-Request-Id; see docs/arch/billing.md for internals and docs/manuals/billing.md for the operational playbook.

Support channel's built-in tooling configuration

Configure the price and whitelist for a channel’s built‑in tools.

tooling-config

Support update user's remained quota

You can update the used quota using the API key of any token, allowing other consumption to be aggregated into the one-api for centralized management.

curl -X POST https://oneapi.laisky.com/api/token/consume \
  -H "Authorization: Bearer <TOKEN_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "add_reason": "async-transcode",
    "add_used_quota": 150
  }'

> Read More

Get request's cost

Each chat completion request will include a X-Oneapi-Request-Id in the returned headers. You can use this request id to request GET /api/cost/request/:request_id to get the cost of this request.

The returned structure is:

type UserRequestCost struct {
  Id          int     `json:"id"`
  CreatedTime int64   `json:"created_time" gorm:"bigint"`
  UserID      int     `json:"user_id"`
  RequestID   string  `json:"request_id"`
  Quota       int64   `json:"quota"`
  CostUSD     float64 `json:"cost_usd" gorm:"-"`
}

Support Tracing info in logs

Support Cached Input

Now supports cached input, which can significantly reduce the cost.

Support Anthropic Prompt caching

Automatically Enable Thinking and Customize Reasoning Format via URL Parameters

Supports two URL parameters: thinking and reasoning_format.

  • thinking: Whether to enable thinking mode, disabled by default.
  • reasoning_format: Specifies the format of the returned reasoning.
    • reasoning_content: DeepSeek official API format, returned in the reasoning_content field.
    • reasoning: OpenRouter format, returned in the reasoning field.
    • thinking: Claude format, returned in the thinking field.
Reasoning Format - reasoning-content
curl --location 'https://oneapi.laisky.com/v1/chat/completions?thinking=true&reasoning_format=reasoning_content' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
    "model": "gpt-5-mini",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "1+1=?"
      }
    ]
  }'

Response:

{
  "id": "resp_01282fbc2c1cd0a90069068d5ae43c819e93f5ca9ebacf4aaa",
  "model": "gpt-5-mini",
  "object": "chat.completion",
  "created": 1762037082,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "2",
        "reasoning_content": "**Calculating addition succinctly**\n\nI need to respond clearly. The user might be asking playfully, so I should keep it concise. The simplest answer is 1 + 1 = 2. It could be fun to mention that in binary, 1 + 1 equals 10, but that's not really necessary since the typical base is decimal. I'll stick with the straightforward response: \"2.\" Maybe I can add a brief note explaining it, like \"Adding one and one gives two,\" but I’ll keep it minimal.",
        "reasoning": "**Calculating addition succinctly**\n\nI need to respond clearly. The user might be asking playfully, so I should keep it concise. The simplest answer is 1 + 1 = 2. It could be fun to mention that in binary, 1 + 1 equals 10, but that's not really necessary since the typical base is decimal. I'll stick with the straightforward response: \"2.\" Maybe I can add a brief note explaining it, like \"Adding one and one gives two,\" but I’ll keep it minimal."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 199,
    "total_tokens": 209,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 0,
      "text_tokens": 0,
      "image_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 192,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0,
      "text_tokens": 0,
      "cached_tokens": 0
    }
  }
}
Reasoning Format - reasoning
curl --location 'https://oneapi.laisky.com/v1/chat/completions?thinking=true&reasoning_format=reasoning' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
    "model": "gpt-5-mini",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "1+1=?"
      }
    ]
  }'

Response:

{
  "id": "resp_0e6222cdcfeabbbf0069068da588b88194964340c1e33fbabb",
  "model": "gpt-5-mini",
  "object": "chat.completion",
  "created": 1762037157,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "2",
        "reasoning": "**Calculating a simple equation**\n\nThe user asked what 1 + 1 equals, which is a straightforward question. I can just respond with \"2.\" Although I could add a simple explanation that 1 plus 1 equals 2, I should keep it concise. So, I’ll stick with the answer \"2\" and perhaps mention \"1 + 1 = 2\" for clarity. It's clear, and there are no concerns here, so I'll give the final response of \"2.\""
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 71,
    "total_tokens": 81,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 0,
      "text_tokens": 0,
      "image_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 64,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0,
      "text_tokens": 0,
      "cached_tokens": 0
    }
  }
}
Reasoning Format - thinking
curl --location 'https://oneapi.laisky.com/v1/chat/completions?thinking=true&reasoning_format=thinking' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
    "model": "gpt-5-mini",
    "max_tokens": 1024,
    "messages": [
      {
      "role": "user",
      "content": "1+1=?"
    }
    ]
  }'

Response:

{
  "id": "resp_099bd53deedec1a80069068dc160d88191a1d3ff4eb82c37bb",
  "model": "gpt-5-mini",
  "object": "chat.completion",
  "created": 1762037185,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "2",
        "thinking": "**Calculating simple arithmetic**\n\nThe user asked a really straightforward question: \"1+1=?\". I should definitely keep it concise, so the answer is simply 2. I could also mention that 1+1 equals 2 in terms of adding integers. But really, just saying \"2\" should suffice. If they're curious for more detail, I can provide a brief explanation. Still, keeping it minimal, I'll just go with \"2\". That's all they need!"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 10,
    "completion_tokens": 71,
    "total_tokens": 81,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 0,
      "text_tokens": 0,
      "image_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 64,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0,
      "text_tokens": 0,
      "cached_tokens": 0
    }
  }
}

OpenAI Features

Support whisper

curl --location 'https://oneapi.laisky.com/v1/audio/transcriptions' \
  --header 'Authorization: Bearer laisky-xxxxxxx' \
  --form 'file=@"postman-cloud:///1efcd71f-7206-4a70-94d1-7727d79d124b"' \
  --form 'model="whisper-1"' \
  --form 'response_format="verbose_json"'

Response:

{
  "task": "transcribe",
  "language": "english",
  "duration": 3.869999885559082,
  "text": "Hello everyone, nice to see you today",
  "segments": [
    {
      "id": 0,
      "seek": 0,
      "start": 0.0,
      "end": 3.680000066757202,
      "text": " Hello everyone, nice to see you today",
      "tokens": [50364, 2425, 1518, 11, 1481, 281, 536, 291, 965, 50548],
      "temperature": 0.0,
      "avg_logprob": -0.44038617610931396,
      "compression_ratio": 0.8604651093482971,
      "no_speech_prob": 0.002639062935486436
    }
  ],
  "usage": {
    "type": "duration",
    "seconds": 4
  }
}

Support openai images edits

curl --location 'https://oneapi.laisky.com/v1/images/edits' \
  --header 'Authorization: sk-xxxxxxx' \
  --form 'image[]=@"postman-cloud:///1f020b33-1ca1-4f10-b6d2-7b12aa70111e"' \
  --form 'image[]=@"postman-cloud:///1f020b33-22c6-4350-8314-063db53618a4"' \
  --form 'prompt="put all items in references image into a gift busket"' \
  --form 'model="gpt-image-1"'

Response:

{
  "created": 1762038453,
  "data": [
    {
      "url": "https://xxxxxxx.png"
    }
  ]
}

Support OpenAI o1/o1-mini/o1-preview

Support gpt-4o-audio

curl --location 'https://oneapi.laisky.com/v1/chat/completions' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
      "model": "gpt-4o-audio-preview",

      "max_tokens": 200,
      "modalities": ["text", "audio"],
      "audio": { "voice": "alloy", "format": "pcm16" },
      "messages": [
          {
              "role": "system",
              "content": "You are a helpful assistant."
          },
          {
              "role": "user",
              "content": [
                  {
                      "type": "text",
                      "text": "what is in this recording"
                  },
                  {
                      "type": "input_audio",
                      "input_audio": {
                          "data": "<BASE64_ENCODED_AUDIO_DATA>",
                          "format": "mp3"
                      }
                  }
              ]
          }
      ]
  }'

Response:

{
  "id": "chatcmpl-CXEuXGd0MagiwenLiOtDhLNMHZs63",
  "object": "chat.completion",
  "created": 1762038177,
  "model": "gpt-4o-audio-preview-2025-06-03",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": null,
        "refusal": null,
        "audio": {
          "id": "audio_690691a2f0248191be5a199d7a49968b",
          "data": "<BASE64_ENCODED_AUDIO_DATA>",
          "expires_at": 1762041778,
          "transcript": "The recording contains a greeting where someone is saying, \"Hello everyone, nice to see you today.\" It sounds like a friendly and casual greeting"
        },
        "annotations": []
      },
      "finish_reason": "length"
    }
  ],
  "usage": {
    "prompt_tokens": 64,
    "completion_tokens": 200,
    "total_tokens": 264,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 38,
      "text_tokens": 26,
      "image_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 159,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0,
      "text_tokens": 41
    }
  },
  "service_tier": "default",
  "system_fingerprint": "fp_363417d4a6"
}

Support OpenAI web search models

support gpt-4o-search-preview & gpt-4o-mini-search-preview

curl --location 'https://oneapi.laisky.com/v1/chat/completions?thinking=true&reasoning_format=thinking' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
    "model": "gpt-4o-mini-search-preview",
    "max_tokens": 1024,
    "stream": false,
    "messages": [
      {
        "role": "user",
        "content": "what'\''s the weather in ottawa canada?"
      }
    ]
  }'

Response:

{
  "id": "resp_0a8e4f5c5f4e4b8f0069068d3f4bb88191f3e1e4b8f4c3faab",
  "model": "gpt-4o-mini-search-preview",
  "object": "chat.completion",
  "created": 1762041234,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "The current weather in Ottawa, Canada is partly cloudy with a temperature of 22°C (72°F). There is a light breeze coming from the northwest at 10 km/h (6 mph). Humidity is at 60%, and there is no precipitation expected today. For more detailed and up-to-date information, please check a reliable weather website or app.",
        "thinking": "**Using web search to find current weather information**\n\nI searched for the latest weather updates for Ottawa, Canada. Based on the most recent data available, I found that the weather is partly cloudy with a temperature of 22°C (72°F). I also noted the wind speed and direction, humidity levels, and the absence of precipitation. This information should help the user understand the current weather conditions in Ottawa."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 15,
    "completion_tokens": 150,
    "total_tokens": 165,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 0,
      "text_tokens": 15,
      "image_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 130,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0,
      "text_tokens": 20,
      "cached_tokens": 0
    }
  }
}

Response:

{
  "id": "chatcmpl-3ba4b046-577a-4cbd-8ebc-80b48607e6ee",
  "object": "chat.completion",
  "created": 1762038412,
  "model": "gpt-4o-mini-search-preview-2025-03-11",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "As of 6:06 PM on Saturday, November 1, 2025, in Ottawa, Canada, the weather is mostly cloudy with a temperature of 38°F (4°C).\n\n## Weather for Ottawa, ON:\nCurrent Conditions: Mostly cloudy, 38°F (4°C)\n\nDaily Forecast:\n* Saturday, November 1: Low: 35°F (1°C), High: 43°F (6°C), Description: Cloudy and breezy with a shower in spots\n* Sunday, November 2: Low: 36°F (2°C), High: 46°F (8°C), Description: Cloudy in the morning, then times of clouds and sun in the afternoon\n* Monday, November 3: Low: 36°F (2°C), High: 51°F (11°C), Description: Cloudy and breezy with showers\n* Tuesday, November 4: Low: 34°F (1°C), High: 52°F (11°C), Description: Mostly sunny and breezy\n* Wednesday, November 5: Low: 36°F (2°C), High: 44°F (7°C), Description: Cloudy with a couple of showers, mainly later\n* Thursday, November 6: Low: 29°F (-1°C), High: 44°F (7°C), Description: A little morning rain; otherwise, cloudy most of the time\n* Friday, November 7: Low: 32°F (0°C), High: 45°F (7°C), Description: Mostly cloudy\n\n\nIn November, Ottawa typically experiences cool and damp conditions, with average high temperatures around 5°C (41°F) and lows near -2°C (28°F). The city usually receives about 84 mm (3.3 inches) of precipitation over 14 days during the month. ([weather2visit.com](https://www.weather2visit.com/north-america/canada/ottawa-november.htm?utm_source=openai)) ",
        "refusal": null,
        "annotations": [
          {
            "type": "url_citation",
            "url_citation": {
              "end_index": 1358,
              "start_index": 1247,
              "title": "Ottawa Weather in November 2025 | Canada Averages | Weather-2-Visit",
              "url": "https://www.weather2visit.com/north-america/canada/ottawa-november.htm?utm_source=openai"
            }
          }
        ]
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 411,
    "total_tokens": 420,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 0,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0
    }
  },
  "system_fingerprint": ""
}

Support gpt-image family for image generation & edits

Support gpt-image-1 & gpt-image-1-mini for image generation and editing.

Draw image:

curl --location 'https://oneapi.laisky.com/v1/images/generations' \
--header 'Content-Type: application/json' \
--header 'Authorization: sk-xxxxxxx' \
--data '{
    "model": "gpt-image-1-mini",
    "prompt": "draw a goose",
    "n": 1,
    "size": "1024x1024",
    "response_format": "b64_json"
}'

Response:

{
  "created": 1763152907,
  "background": "opaque",
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANS..."
    }
  ],
  "output_format": "png",
  "quality": "high",
  "size": "1536x1024",
  "usage": {
    "input_tokens": 437,
    "input_tokens_details": {
      "image_tokens": 388,
      "text_tokens": 49
    },
    "output_tokens": 6208,
    "total_tokens": 6645
  }
}

Edit image:

curl --location 'https://oneapi.laisky.com/v1/images/edits' \
  --header 'Authorization: sk-xxxxxxx' \
  --form 'image[]=@"postman-cloud:///1f020b33-1ca1-4f10-b6d2-7b12aa70111e"' \
  --form 'image[]=@"postman-cloud:///1f020b33-22c6-4350-8314-063db53618a4"' \
  --form 'prompt="put all items in references image into a gift busket"' \
  --form 'model="gpt-image-1-mini"'

Response:

{
  "created": 1763152907,
  "background": "opaque",
  "data": [
    {
      "b64_json": "iVBORw0KGgoAAAANS..."
    }
  ],
  "output_format": "png",
  "quality": "high",
  "size": "1536x1024",
  "usage": {
    "input_tokens": 437,
    "input_tokens_details": {
      "image_tokens": 388,
      "text_tokens": 49
    },
    "output_tokens": 6208,
    "total_tokens": 6645
  }
}

Support o3-mini & o3 & o4-mini & gpt-4.1 & o3-pro & reasoning content

Support OpenAI Response API

curl --location 'https://oneapi.laisky.com/v1/responses' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
      "model": "gemini-2.5-flash",
      "input": "Tell me a three sentence bedtime story about a unicorn."
    }'

Response:

{
  "id": "resp-2025110123121283977003996295227",
  "object": "response",
  "created_at": 1762038734,
  "status": "completed",
  "model": "gemini-2.5-flash",
  "output": [
    {
      "type": "message",
      "status": "completed",
      "role": "assistant",
      "content": [
        {
          "type": "output_text",
          "text": "Lily the unicorn lived in a meadow where rainbows touched the ground. Every evening, she would gallop beneath the starry sky, her horn glowing like a tiny lantern. When she finally nestled into her bed of soft moss, all the little forest creatures drifted off to sleep, feeling safe and warm."
        }
      ]
    }
  ],
  "usage": {
    "input_tokens": 12,
    "output_tokens": 151,
    "total_tokens": 163
  },
  "parallel_tool_calls": false
}

Support gpt-5 family

gpt-5.1-chat-latest / gpt-5.1 / gpt-5.1-2025-11-13 / gpt-5.1-codex / gpt-5.1-codex-mini

gpt-5-chat-latest / gpt-5 / gpt-5-mini / gpt-5-nano / gpt-5-codex / gpt-5.1-codex-max/ gpt-5-pro

Support o3-deep-research & o4-mini-deep-research

curl --location 'https://oneapi.laisky.com/v1/chat/completions?thinking=true&reasoning_format=thinking' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
    "model": "o4-mini-deep-research",
    "max_tokens": 9086,
    "stream": false,
    "messages": [
      {
        "role": "user",
        "content": "what'\''s the weather in ottawa canada?"
      }
    ]
  }'

Response:

Note

To run deep‑research successfully, you need to configure a comparatively large max_tokens value. This response was cut off due to the max_tokens limit you set.

{
  "id": "resp_0457d54ec43cbbe2006906945811f081a28fce9f1839c1fa67",
  "model": "o4-mini-deep-research",
  "object": "chat.completion",
  "created": 1762038872,
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "",
        "thinking": "**Finding current weather in Ottawa**\n\nThe user asked about the current weather in Ottawa, Canada, which means I need to retrieve up-to-date weather information. I can't rely on past knowledge here; I should search for current weather reports specifically for that location. It's November 1, 2025, so it's essential to consider both the time and place as I look for reliable sources, like local weather sites or official forecasts, to provide the user with accurate information.**Searching for current weather**\n\nThis looks like a weather query that requires me to retrieve the latest information. I need to remember that the instructions emphasize using searches for up-to-date data and not relying solely on past knowledge. Since the guidelines don't prohibit weather queries, I should feel safe in proceeding. I’ll look up the current weather for Ottawa, Canada, using a browser search to ensure I provide accurate and timely information for the user."
      },
      "finish_reason": "length"
    }
  ],
  "usage": {
    "prompt_tokens": 31134,
    "completion_tokens": 2608,
    "total_tokens": 33742,
    "prompt_tokens_details": {
      "cached_tokens": 0,
      "audio_tokens": 0,
      "text_tokens": 0,
      "image_tokens": 0
    },
    "completion_tokens_details": {
      "reasoning_tokens": 2624,
      "audio_tokens": 0,
      "accepted_prediction_tokens": 0,
      "rejected_prediction_tokens": 0,
      "text_tokens": 0,
      "cached_tokens": 0
    }
  }
}

Support Codex Cli

# vi $HOME/.codex/config.toml

model = "gemini-2.5-flash"
model_provider = "laisky"

[model_providers.laisky]
# Name of the provider that will be displayed in the Codex UI.
name = "Laisky"
# The path `/chat/completions` will be amended to this URL to make the POST
# request for the chat completions.
base_url = "https://oneapi.laisky.com/v1"
# If `env_key` is set, identifies an environment variable that must be set when
# using Codex with this provider. The value of the environment variable must be
# non-empty and will be used in the `Bearer TOKEN` HTTP header for the POST request.
env_key = "sk-xxxxxxx"
# Valid values for wire_api are "chat" and "responses". Defaults to "chat" if omitted.
wire_api = "responses"
# If necessary, extra query params that need to be added to the URL.
# See the Azure example below.
query_params = {}

Support Sora

https://platform.openai.com/docs/guides/video-generation

Create Video Task:

curl --location 'https://oneapi.laisky.com/v1/videos' \
  --header 'Authorization: sk-xxxxxxx' \
  --form 'prompt="aurora"' \
  --form 'model="sora-2"' \
  --form 'seconds="4"' \
  --form 'size="1280x720"'

Response:

{
  "id": "video_691608967fe8819399e710799dae2ae708872b008b63ff61",
  "object": "video",
  "created_at": 1763051670,
  "status": "queued",
  "completed_at": null,
  "error": null,
  "expires_at": null,
  "model": "sora-2",
  "progress": 0,
  "prompt": "aurora",
  "remixed_from_video_id": null,
  "seconds": "4",
  "size": "1280x720"
}

Get Video Task Status:

curl --location 'https://oneapi.laisky.com/v1/videos/video_691608967fe8819399e710799dae2ae708872b008b63ff61'
  --header 'Authorization: sk-xxxxxxx'

Response:

{
  "id": "video_691611812ca88190bfb123716dcc953a089a232f54b02b21",
  "object": "video",
  "created_at": 1763053953,
  "status": "completed",
  "completed_at": 1763054021,
  "error": null,
  "expires_at": 1763057621,
  "model": "sora-2",
  "progress": 100,
  "prompt": "aurora",
  "remixed_from_video_id": null,
  "seconds": "4",
  "size": "1280x720"
}

Download Video:

curl --location 'https://oneapi.laisky.com/v1/videos/video_691611812ca88190bfb123716dcc953a089a232f54b02b21/content'
  --header 'Authorization: sk-xxxxxxx'

Anthropic (Claude) Features

(Merged) Support aws claude

Support claude-3-7-sonnet & thinking

By default, the thinking mode is not enabled. You need to manually pass the thinking field in the request body to enable it.

Stream

Non-Stream

Support /v1/messages Claude Messages API

Support Claude Code
export ANTHROPIC_MODEL="openai/gpt-oss-120b"
export ANTHROPIC_BASE_URL="https://oneapi.laisky.com/"
export ANTHROPIC_AUTH_TOKEN="sk-xxxxxxx"

You can use any model you like for Claude Code, even if the model doesn’t natively support the Claude Messages API.

Support Claude 4.x Models

claude-opus-4-0 / claude-opus-4-1 / claude-opus-4-5 / claude-sonnet-4-0 / claude-sonnet-4-5 / claude-haiku-4-5

Google (Gemini & Vertex) Features

Support gemini-2.0-flash-exp

Support gemini-2.0-flash

Support gemini-2.0-flash-thinking-exp-01-21

Support Vertex Imagen3

Support gemini multimodal output #2197

Support gemini-2.5-pro

Support GCP Vertex gloabl region and gemini-2.5-pro-preview-06-05

Support gemini-2.5-flash-image-preview & imagen-4 series

Support gemini-3 family

Support gemini-3-pro-preview, gemini-3-pro-image-preview

OpenCode Support

OpenCode logo

opencode.ai is an AI coding agent built for the terminal. OpenCode is fully open source, giving you control and freedom to use any provider, any model, and any editor. It's available as both a CLI and TUI.

One‑API integrates seamlessly with OpenCode: you can connect any One‑API endpoint and use all your unified models through OpenCode's interface (both CLI and TUI).

To get started, create or edit ~/.config/opencode/opencode.json like this:

Using OpenAI SDK:

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "one-api": {
      "npm": "@ai-sdk/openai",
      "name": "One API",
      "options": {
        "baseURL": "https://oneapi.laisky.com/v1",
        "apiKey": "<ONEAPI_TOKEN_KEY>"
      },
      "models": {
        "gpt-4.1-2025-04-14": {
          "name": "GPT 4.1"
        }
      }
    }
  }
}

Using Anthropic SDK:

{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "one-api-anthropic": {
      "npm": "@ai-sdk/anthropic",
      "name": "One API (Anthropic)",
      "options": {
        "baseURL": "https://oneapi.laisky.com/v1",
        "apiKey": "<ONEAPI_TOKEN_KEY>"
      },
      "models": {
        "claude-sonnet-4-5": {
          "name": "Claude Sonnet 4.5"
        }
      }
    }
  }
}

AWS Features

Support AWS cross-region inferences

Support AWS BedRock Inference Profile

Replicate Features

Support replicate flux & remix

Support replicate chat models

DeepSeek Features

Support deepseek-reasoner

OpenRouter Features

Support OpenRouter's reasoning content

By default, the thinking mode is automatically enabled for the deepseek-r1 model, and the response is returned in the open-router format.

Cohere

Support Cohere Command R & Rerank

curl --location 'https://oneapi.laisky.com/v1/rerank' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: sk-xxxxxxx' \
  --data '{
      "model": "rerank-v3.5",
      "query": "What is the capital of the United States?",
      "top_n": 3,
      "documents": [
          "Carson City is the capital city of the American state of Nevada.",
          "The Commonwealth of the Northern Mariana Islands is a group of islands in the Pacific Ocean. Its capital is Saipan.",
          "Washington, D.C. (also known as simply Washington or D.C., and officially as the District of Columbia) is the capital of the United States. It is a federal district.",
          "Capitalization or capitalisation in English grammar is the use of a capital letter at the start of a word. English usage varies from capitalization in other languages.",
          "Capital punishment has existed in the United States since beforethe United States was a country. As of 2017, capital punishment is legal in 30 of the 50 states."
      ]
  }'

Response:

{
  "object": "cohere.rerank",
  "model": "rerank-v3.5",
  "id": "ff9458ce-318b-4317-ad49-f8654c976dff",
  "results": [
    {
      "index": 2,
      "relevance_score": 0.8742601
    },
    {
      "index": 0,
      "relevance_score": 0.17292508
    },
    {
      "index": 4,
      "relevance_score": 0.10793502
    }
  ],
  "meta": {
    "api_version": {
      "version": "2",
      "is_experimental": false
    },
    "billed_units": {
      "search_units": 1
    }
  },
  "usage": {
    "prompt_tokens": 153,
    "total_tokens": 153
  }
}

Coze Features

Support coze oauth authentication

Moonshot Features

Support kimi-k2 Family

Support:

  • kimi-k2-0905-preview
  • kimi-k2-0711-preview
  • kimi-k2-turbo-preview
  • kimi-k2-thinking
  • kimi-k2-thinking-turbo

GLM Features

Support:

  • glm-zero-preview
  • glm-3-turbo
  • cogview-3-flash
  • codegeex-4
  • embedding-3
  • embedding-2

Support GLM-4 Family

  • glm-4.6
  • glm-4.5
  • glm-4.5-x
  • glm-4.5-air
  • glm-4.5-airx
  • glm-4.5-flash
  • glm-4v-flash

XAI / Grok Features

Support XAI/Grok Text & Image Models

Black Forest Labs Features

Support black-forest-labs/flux-kontext-pro

Bug Fixes & Enterprise-Grade Improvements (Including Security Enhancements)

Note

For additional enterprise-grade improvements, including security enhancements (e.g., vulnerability fixes), you can also view these pull requests here.

About

OpenRouter’s open‑source alternative. Multi-model/Multi-API-format/Multi-tenant LLM API aggregation platform.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 58.7%
  • JavaScript 20.1%
  • TypeScript 18.0%
  • CSS 2.7%
  • Shell 0.2%
  • SCSS 0.1%
  • Other 0.2%