curl --request POST \
--url https://openrouter.ai/api/v1/byok \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"key": "sk-proj-abc123...",
"name": "Production OpenAI Key",
"provider": "openai"
}
'import requests
url = "https://openrouter.ai/api/v1/byok"
payload = {
"key": "sk-proj-abc123...",
"name": "Production OpenAI Key",
"provider": "openai"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({key: 'sk-proj-abc123...', name: 'Production OpenAI Key', provider: 'openai'})
};
fetch('https://openrouter.ai/api/v1/byok', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://openrouter.ai/api/v1/byok",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'key' => 'sk-proj-abc123...',
'name' => 'Production OpenAI Key',
'provider' => 'openai'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://openrouter.ai/api/v1/byok"
payload := strings.NewReader("{\n \"key\": \"sk-proj-abc123...\",\n \"name\": \"Production OpenAI Key\",\n \"provider\": \"openai\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://openrouter.ai/api/v1/byok")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"key\": \"sk-proj-abc123...\",\n \"name\": \"Production OpenAI Key\",\n \"provider\": \"openai\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://openrouter.ai/api/v1/byok")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"key\": \"sk-proj-abc123...\",\n \"name\": \"Production OpenAI Key\",\n \"provider\": \"openai\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"allowed_api_key_hashes": null,
"allowed_models": null,
"allowed_user_ids": null,
"created_at": "2025-08-24T10:30:00Z",
"disabled": false,
"id": "11111111-2222-3333-4444-555555555555",
"is_byok_only": false,
"is_fallback": false,
"is_required": false,
"label": "sk-...AbCd",
"name": "Production OpenAI Key",
"provider": "openai",
"sort_order": 0,
"workspace_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": 400,
"message": "Invalid request parameters"
}
}{
"error": {
"code": 401,
"message": "Missing Authentication header"
}
}{
"error": {
"code": 403,
"message": "Only management keys can perform this operation"
}
}{
"error": {
"code": 500,
"message": "Internal Server Error"
}
}Create a BYOK provider credential
Create a new bring-your-own-key (BYOK) provider credential. The raw key is encrypted at rest and never returned in API responses. When workspace_id is omitted, the credential is created in the default workspace; if that default has been deleted, the request returns a 400 and you must pass workspace_id explicitly. Treat the raw key as write-only; it is never returned after creation. Use allowed_api_key_hashes to restrict the credential to specific OpenRouter API keys. Management key required.
curl --request POST \
--url https://openrouter.ai/api/v1/byok \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"key": "sk-proj-abc123...",
"name": "Production OpenAI Key",
"provider": "openai"
}
'import requests
url = "https://openrouter.ai/api/v1/byok"
payload = {
"key": "sk-proj-abc123...",
"name": "Production OpenAI Key",
"provider": "openai"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({key: 'sk-proj-abc123...', name: 'Production OpenAI Key', provider: 'openai'})
};
fetch('https://openrouter.ai/api/v1/byok', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://openrouter.ai/api/v1/byok",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'key' => 'sk-proj-abc123...',
'name' => 'Production OpenAI Key',
'provider' => 'openai'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://openrouter.ai/api/v1/byok"
payload := strings.NewReader("{\n \"key\": \"sk-proj-abc123...\",\n \"name\": \"Production OpenAI Key\",\n \"provider\": \"openai\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://openrouter.ai/api/v1/byok")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"key\": \"sk-proj-abc123...\",\n \"name\": \"Production OpenAI Key\",\n \"provider\": \"openai\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://openrouter.ai/api/v1/byok")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"key\": \"sk-proj-abc123...\",\n \"name\": \"Production OpenAI Key\",\n \"provider\": \"openai\"\n}"
response = http.request(request)
puts response.read_body{
"data": {
"allowed_api_key_hashes": null,
"allowed_models": null,
"allowed_user_ids": null,
"created_at": "2025-08-24T10:30:00Z",
"disabled": false,
"id": "11111111-2222-3333-4444-555555555555",
"is_byok_only": false,
"is_fallback": false,
"is_required": false,
"label": "sk-...AbCd",
"name": "Production OpenAI Key",
"provider": "openai",
"sort_order": 0,
"workspace_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": 400,
"message": "Invalid request parameters"
}
}{
"error": {
"code": 401,
"message": "Missing Authentication header"
}
}{
"error": {
"code": 403,
"message": "Only management keys can perform this operation"
}
}{
"error": {
"code": 500,
"message": "Internal Server Error"
}
}Authorizations
API key as bearer token in Authorization header
Body
The raw provider API key or credential. This value is encrypted at rest and never returned in API responses.
1"sk-proj-abc123..."
The upstream provider this credential authenticates against, as a lowercase slug (e.g. openai, anthropic, amazon-bedrock).
ai21, aion-labs, akashml, alibaba, amazon-bedrock, amazon-nova, ambient, anthropic, arcee-ai, atlas-cloud, avian, azure, baidu, baseten, black-forest-labs, byteplus, cerebras, chutes, cirrascale, clarifai, cloudflare, cohere, coreweave, cosine, crusoe, darkbloom, databricks, decart, deepgram, deepinfra, deepseek, dekallm, digitalocean, featherless, fireworks, fish-audio, friendli, gmicloud, google-ai-studio, google-vertex, groq, heygen, inception, inceptron, inferact-vllm, inference-net, infermatic, inflection, io-net, ionstream, krea, liquid, makora, mancer, mara, meta, minimax, mistral, modal, modelrun, modular, moonshotai, morph, nebius, nex-agi, nextbit, novita, nvidia, ollama, open-inference, openai, parasail, perceptron, perplexity, phala, poolside, primeintellect, quiver, recraft, reka, relace, runway, sail-research, sakana, sakana-ai, sambanova, seed, siliconflow, sourceful, stepfun, streamlake, switchpoint, tencent, tenstorrent, thinkingmachines, together, upstage, venice, voyageai, wafer, wandb, wandb-legacy, xai, xiaomi, z-ai "openai"
Optional allowlist of OpenRouter API key hashes (api_keys.hash) that may use this credential. null means no restriction. Must contain at least one hash if provided. Hashes that do not belong to your account return a 400.
1 - 100 elements^[a-f0-9]{64}$[
"f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943"
]
Optional allowlist of model slugs this credential may be used for. null means no restriction.
100null
Optional allowlist of user IDs that may use this credential. null means no restriction.
100null
Whether this credential should be created in a disabled state.
false
Whether OpenRouter's shared endpoints on this provider are removed for every model, including models outside allowed_models and after all of your keys for the provider fail. The provider is skipped instead of spending OpenRouter credits. Only valid on non-fallback credentials. Defaults to false.
false
Whether this credential is treated as a fallback — used only after non-fallback keys for the same provider have been tried. Cannot be combined with is_byok_only.
false
Whether OpenRouter's shared endpoints on this provider are removed for the models this credential applies to (its allowed_models, or every model when null). Requests for those models run only on your keys; models outside the allowlist may still fall back to shared capacity on this provider. Defaults to false.
false
Optional human-readable name for the credential.
255"Production OpenAI Key"
Optional workspace ID to scope the credential to. When omitted, the credential is created in the account's default workspace; if that default has been deleted, the request returns a 400 and you must pass workspace_id explicitly.
"550e8400-e29b-41d4-a716-446655440000"
Response
BYOK credential created successfully
The created BYOK credential.
Show child attributes
Show child attributes
{
"allowed_api_key_hashes": null,
"allowed_models": null,
"allowed_user_ids": null,
"created_at": "2025-08-24T10:30:00Z",
"disabled": false,
"id": "11111111-2222-3333-4444-555555555555",
"is_byok_only": false,
"is_fallback": false,
"is_required": false,
"label": "sk-...AbCd",
"name": "Production OpenAI Key",
"provider": "openai",
"sort_order": 0,
"workspace_id": "550e8400-e29b-41d4-a716-446655440000"
}