curl --request POST \
--url https://api.airctrl.dev/v1/records/{id}/rotate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"dekVersion": 2,
"sourceWrappedDek": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ciphertext": "<string>",
"cipherMeta": {},
"dekTransition": {
"fromDekVersion": 2,
"toDekVersion": 3,
"ciphertext": "<string>",
"cipherMeta": {}
},
"wrappedDek": {},
"sourceProjectKeyVersion": 2,
"environmentValues": [
{
"ciphertext": "<string>",
"cipherMeta": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
],
"recipientWrappers": [
{
"userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"recipientPublicKeyB64": "<string>",
"wrappedDek": {}
}
],
"projectWrappedDek": {},
"projectKeyVersion": 2
}
'import requests
url = "https://api.airctrl.dev/v1/records/{id}/rotate"
payload = {
"dekVersion": 2,
"sourceWrappedDek": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ciphertext": "<string>",
"cipherMeta": {},
"dekTransition": {
"fromDekVersion": 2,
"toDekVersion": 3,
"ciphertext": "<string>",
"cipherMeta": {}
},
"wrappedDek": {},
"sourceProjectKeyVersion": 2,
"environmentValues": [
{
"ciphertext": "<string>",
"cipherMeta": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
],
"recipientWrappers": [
{
"userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"recipientPublicKeyB64": "<string>",
"wrappedDek": {}
}
],
"projectWrappedDek": {},
"projectKeyVersion": 2
}
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({
dekVersion: 2,
sourceWrappedDek: {},
sourceVersionId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
ciphertext: '<string>',
cipherMeta: {},
dekTransition: {fromDekVersion: 2, toDekVersion: 3, ciphertext: '<string>', cipherMeta: {}},
wrappedDek: {},
sourceProjectKeyVersion: 2,
environmentValues: [
{
ciphertext: '<string>',
cipherMeta: {},
sourceVersionId: '3c90c3cc-0d44-4b50-8888-8dd25736052a'
}
],
recipientWrappers: [
{
userId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
recipientPublicKeyB64: '<string>',
wrappedDek: {}
}
],
projectWrappedDek: {},
projectKeyVersion: 2
})
};
fetch('https://api.airctrl.dev/v1/records/{id}/rotate', 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.airctrl.dev/v1/records/{id}/rotate",
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([
'dekVersion' => 2,
'sourceWrappedDek' => [
],
'sourceVersionId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'ciphertext' => '<string>',
'cipherMeta' => [
],
'dekTransition' => [
'fromDekVersion' => 2,
'toDekVersion' => 3,
'ciphertext' => '<string>',
'cipherMeta' => [
]
],
'wrappedDek' => [
],
'sourceProjectKeyVersion' => 2,
'environmentValues' => [
[
'ciphertext' => '<string>',
'cipherMeta' => [
],
'sourceVersionId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a'
]
],
'recipientWrappers' => [
[
'userId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'recipientPublicKeyB64' => '<string>',
'wrappedDek' => [
]
]
],
'projectWrappedDek' => [
],
'projectKeyVersion' => 2
]),
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.airctrl.dev/v1/records/{id}/rotate"
payload := strings.NewReader("{\n \"dekVersion\": 2,\n \"sourceWrappedDek\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"dekTransition\": {\n \"fromDekVersion\": 2,\n \"toDekVersion\": 3,\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {}\n },\n \"wrappedDek\": {},\n \"sourceProjectKeyVersion\": 2,\n \"environmentValues\": [\n {\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n }\n ],\n \"recipientWrappers\": [\n {\n \"userId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"recipientPublicKeyB64\": \"<string>\",\n \"wrappedDek\": {}\n }\n ],\n \"projectWrappedDek\": {},\n \"projectKeyVersion\": 2\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://api.airctrl.dev/v1/records/{id}/rotate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"dekVersion\": 2,\n \"sourceWrappedDek\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"dekTransition\": {\n \"fromDekVersion\": 2,\n \"toDekVersion\": 3,\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {}\n },\n \"wrappedDek\": {},\n \"sourceProjectKeyVersion\": 2,\n \"environmentValues\": [\n {\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n }\n ],\n \"recipientWrappers\": [\n {\n \"userId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"recipientPublicKeyB64\": \"<string>\",\n \"wrappedDek\": {}\n }\n ],\n \"projectWrappedDek\": {},\n \"projectKeyVersion\": 2\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.airctrl.dev/v1/records/{id}/rotate")
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 \"dekVersion\": 2,\n \"sourceWrappedDek\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"dekTransition\": {\n \"fromDekVersion\": 2,\n \"toDekVersion\": 3,\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {}\n },\n \"wrappedDek\": {},\n \"sourceProjectKeyVersion\": 2,\n \"environmentValues\": [\n {\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n }\n ],\n \"recipientWrappers\": [\n {\n \"userId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"recipientPublicKeyB64\": \"<string>\",\n \"wrappedDek\": {}\n }\n ],\n \"projectWrappedDek\": {},\n \"projectKeyVersion\": 2\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"data": {
"recordId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"dekVersion": 2
}
}{
"ok": false,
"error": {
"code": "bad_request",
"message": "Request validation failed",
"details": [
"Check the submitted values."
]
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "unauthorized",
"message": "Authentication is required"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "forbidden",
"message": "not_authorized"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "conflict",
"message": "idempotency_key_reused_with_different_params"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "rate_limited",
"message": "Too many requests"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "internal_error",
"message": "Internal server error"
},
"requestId": "req_example"
}Rotate a record key
Replaces the record DEK. General replaces one ciphertext; an Environment record must supply every populated variant with its current version, all encrypted under the new DEK. The client also archives the previous DEK encrypted under the new DEK. One transaction updates the archive, variants and wrappers or none. Requires records:rotate.
curl --request POST \
--url https://api.airctrl.dev/v1/records/{id}/rotate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"dekVersion": 2,
"sourceWrappedDek": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ciphertext": "<string>",
"cipherMeta": {},
"dekTransition": {
"fromDekVersion": 2,
"toDekVersion": 3,
"ciphertext": "<string>",
"cipherMeta": {}
},
"wrappedDek": {},
"sourceProjectKeyVersion": 2,
"environmentValues": [
{
"ciphertext": "<string>",
"cipherMeta": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
],
"recipientWrappers": [
{
"userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"recipientPublicKeyB64": "<string>",
"wrappedDek": {}
}
],
"projectWrappedDek": {},
"projectKeyVersion": 2
}
'import requests
url = "https://api.airctrl.dev/v1/records/{id}/rotate"
payload = {
"dekVersion": 2,
"sourceWrappedDek": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"ciphertext": "<string>",
"cipherMeta": {},
"dekTransition": {
"fromDekVersion": 2,
"toDekVersion": 3,
"ciphertext": "<string>",
"cipherMeta": {}
},
"wrappedDek": {},
"sourceProjectKeyVersion": 2,
"environmentValues": [
{
"ciphertext": "<string>",
"cipherMeta": {},
"sourceVersionId": "3c90c3cc-0d44-4b50-8888-8dd25736052a"
}
],
"recipientWrappers": [
{
"userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"recipientPublicKeyB64": "<string>",
"wrappedDek": {}
}
],
"projectWrappedDek": {},
"projectKeyVersion": 2
}
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({
dekVersion: 2,
sourceWrappedDek: {},
sourceVersionId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
ciphertext: '<string>',
cipherMeta: {},
dekTransition: {fromDekVersion: 2, toDekVersion: 3, ciphertext: '<string>', cipherMeta: {}},
wrappedDek: {},
sourceProjectKeyVersion: 2,
environmentValues: [
{
ciphertext: '<string>',
cipherMeta: {},
sourceVersionId: '3c90c3cc-0d44-4b50-8888-8dd25736052a'
}
],
recipientWrappers: [
{
userId: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
recipientPublicKeyB64: '<string>',
wrappedDek: {}
}
],
projectWrappedDek: {},
projectKeyVersion: 2
})
};
fetch('https://api.airctrl.dev/v1/records/{id}/rotate', 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.airctrl.dev/v1/records/{id}/rotate",
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([
'dekVersion' => 2,
'sourceWrappedDek' => [
],
'sourceVersionId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'ciphertext' => '<string>',
'cipherMeta' => [
],
'dekTransition' => [
'fromDekVersion' => 2,
'toDekVersion' => 3,
'ciphertext' => '<string>',
'cipherMeta' => [
]
],
'wrappedDek' => [
],
'sourceProjectKeyVersion' => 2,
'environmentValues' => [
[
'ciphertext' => '<string>',
'cipherMeta' => [
],
'sourceVersionId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a'
]
],
'recipientWrappers' => [
[
'userId' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'recipientPublicKeyB64' => '<string>',
'wrappedDek' => [
]
]
],
'projectWrappedDek' => [
],
'projectKeyVersion' => 2
]),
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.airctrl.dev/v1/records/{id}/rotate"
payload := strings.NewReader("{\n \"dekVersion\": 2,\n \"sourceWrappedDek\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"dekTransition\": {\n \"fromDekVersion\": 2,\n \"toDekVersion\": 3,\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {}\n },\n \"wrappedDek\": {},\n \"sourceProjectKeyVersion\": 2,\n \"environmentValues\": [\n {\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n }\n ],\n \"recipientWrappers\": [\n {\n \"userId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"recipientPublicKeyB64\": \"<string>\",\n \"wrappedDek\": {}\n }\n ],\n \"projectWrappedDek\": {},\n \"projectKeyVersion\": 2\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://api.airctrl.dev/v1/records/{id}/rotate")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"dekVersion\": 2,\n \"sourceWrappedDek\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"dekTransition\": {\n \"fromDekVersion\": 2,\n \"toDekVersion\": 3,\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {}\n },\n \"wrappedDek\": {},\n \"sourceProjectKeyVersion\": 2,\n \"environmentValues\": [\n {\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n }\n ],\n \"recipientWrappers\": [\n {\n \"userId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"recipientPublicKeyB64\": \"<string>\",\n \"wrappedDek\": {}\n }\n ],\n \"projectWrappedDek\": {},\n \"projectKeyVersion\": 2\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.airctrl.dev/v1/records/{id}/rotate")
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 \"dekVersion\": 2,\n \"sourceWrappedDek\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"dekTransition\": {\n \"fromDekVersion\": 2,\n \"toDekVersion\": 3,\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {}\n },\n \"wrappedDek\": {},\n \"sourceProjectKeyVersion\": 2,\n \"environmentValues\": [\n {\n \"ciphertext\": \"<string>\",\n \"cipherMeta\": {},\n \"sourceVersionId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\"\n }\n ],\n \"recipientWrappers\": [\n {\n \"userId\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"recipientPublicKeyB64\": \"<string>\",\n \"wrappedDek\": {}\n }\n ],\n \"projectWrappedDek\": {},\n \"projectKeyVersion\": 2\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"data": {
"recordId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"dekVersion": 2
}
}{
"ok": false,
"error": {
"code": "bad_request",
"message": "Request validation failed",
"details": [
"Check the submitted values."
]
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "unauthorized",
"message": "Authentication is required"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "forbidden",
"message": "not_authorized"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "conflict",
"message": "idempotency_key_reused_with_different_params"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "rate_limited",
"message": "Too many requests"
},
"requestId": "req_example"
}{
"ok": false,
"error": {
"code": "internal_error",
"message": "Internal server error"
},
"requestId": "req_example"
}Authorizations
Human personal access token (sk-actrl-pat-...).
Headers
Stable key for safely retrying this write. Reuse the same key only with the same request body; results are retained for 24 hours and conflicting reuse returns 409.
Path Parameters
Body
- Option 1
- Option 2
Record DEK version read before opening its source wrapper.
x >= 1Exact encrypted source wrapper opened by the client; never plaintext key material.
Current content version read by the client; null for an empty Environment variant or an unversioned legacy record.
General value encrypted with the new record key; null for Environment records.
Client-generated General encryption metadata.
Show child attributes
Show child attributes
New record key encrypted for the owner.
Required only when the source is the project copy; omit for an individual wrapper.
x >= 1For Environment records, submit exactly every populated variant with its source version. The entire DEK replacement is atomic.
Show child attributes
Show child attributes
Exact existing per-record recipient set, excluding the caller. Echo the public identity used to seal each wrapper. Omitted, extra or stale recipients reject the entire replacement.
- Option 1
- Option 2
Show child attributes
Show child attributes
Record key encrypted for the project key. Required when replacing an existing project copy; otherwise optional.
Required when projectWrappedDek is sent. Version of the project key used by the client; stale or pending re-key material is rejected.
x >= 1