curl --request PATCH \
--url https://api.trycarhub.com/mgmt/v1/api-keys/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"scopes": [
"<string>"
]
}
'import requests
url = "https://api.trycarhub.com/mgmt/v1/api-keys/{id}"
payload = { "scopes": ["<string>"] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({scopes: ['<string>']})
};
fetch('https://api.trycarhub.com/mgmt/v1/api-keys/{id}', 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://api.trycarhub.com/mgmt/v1/api-keys/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'scopes' => [
'<string>'
]
]),
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://api.trycarhub.com/mgmt/v1/api-keys/{id}"
payload := strings.NewReader("{\n \"scopes\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.trycarhub.com/mgmt/v1/api-keys/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"scopes\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trycarhub.com/mgmt/v1/api-keys/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"scopes\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"is_staging": false,
"id": "key_9TbR3xLm",
"object": "api_key",
"name": "Production — vehicle worker",
"prefix": "chk_live_a1b2",
"livemode": true,
"scopes": [
"<string>"
],
"created": 1755300000,
"last_used_at": 1755300000,
"revoked_at": 1755300000,
"created_by": "usr_5KpL2wQx",
"expires_at": 1755300000,
"rotates_at": 1755300000
}Update API key scopes
Admin or owner with current membership. Only scopes may be changed. Rotation preserves scopes exactly.
curl --request PATCH \
--url https://api.trycarhub.com/mgmt/v1/api-keys/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"scopes": [
"<string>"
]
}
'import requests
url = "https://api.trycarhub.com/mgmt/v1/api-keys/{id}"
payload = { "scopes": ["<string>"] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({scopes: ['<string>']})
};
fetch('https://api.trycarhub.com/mgmt/v1/api-keys/{id}', 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://api.trycarhub.com/mgmt/v1/api-keys/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'scopes' => [
'<string>'
]
]),
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://api.trycarhub.com/mgmt/v1/api-keys/{id}"
payload := strings.NewReader("{\n \"scopes\": [\n \"<string>\"\n ]\n}")
req, _ := http.NewRequest("PATCH", 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.patch("https://api.trycarhub.com/mgmt/v1/api-keys/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"scopes\": [\n \"<string>\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.trycarhub.com/mgmt/v1/api-keys/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"scopes\": [\n \"<string>\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"is_staging": false,
"id": "key_9TbR3xLm",
"object": "api_key",
"name": "Production — vehicle worker",
"prefix": "chk_live_a1b2",
"livemode": true,
"scopes": [
"<string>"
],
"created": 1755300000,
"last_used_at": 1755300000,
"revoked_at": 1755300000,
"created_by": "usr_5KpL2wQx",
"expires_at": 1755300000,
"rotates_at": 1755300000
}Authorizations
Short-lived JWT issued by the CarHub auth service (Better Auth), verified against its
JWKS. Claims: sub (user), org_id (active organisation) and role
(owner | admin | member | billing_manager). Used by the dashboard for /mgmt/v1/… only — it is never
accepted on /v1/….
Path Parameters
API key identifier (not the secret).
^key_[1-9A-HJ-NP-Za-km-z]{8,32}$Body
Response
Updated key, without secret
An organisation API key. The secret is never returned after creation.
Staging classification. Requires live mode and uses the organisation's shared live credits.
"key_9TbR3xLm"
"api_key""Production — vehicle worker"
Readable head of the key, enough to identify it in your logs.
"chk_live_a1b2"
Normalized scopes. Empty grants no business access. Wildcard grants no SDK permission. SDK write implies SDK read; storage write implies storage read.
Epoch seconds, UTC.
1755300000
Epoch seconds, UTC.
1755300000
Epoch seconds, UTC.
1755300000
User who created the key, kept for audit. Revoking that user does not affect the key.
"usr_5KpL2wQx"
Scheduled expiry, when the key was minted with one. Null for a perpetual key.
1755300000
End of the grace period of a rotated key: after this instant the previous secret stops working. Null when the key was never rotated.
1755300000