curl --request PUT \
--url https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"document": {}
}'import requests
url = "https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy"
payload = { "document": {} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({document: {}})
};
fetch('https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy', 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://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'document' => [
]
]),
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://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy"
payload := strings.NewReader("{\n \"document\": {}\n}")
req, _ := http.NewRequest("PUT", 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.put("https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"document\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"document\": {}\n}"
response = http.request(request)
puts response.read_body{
"document": {}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}Set the topic's resource policy
Stores an access policy on the topic — the cross-account door. A principal outside the owning account may publish to or subscribe on this topic only when BOTH its own identity policy allows the action on this topic’s CRN AND this policy grants it (bilateral consent, matching bucket policies).
Statements may grant only notifications:Publish and
notifications:Subscribe. Principals: *, an org CRN
(crn:iam:::org/<org-id>), an account CRN
(crn:iam:::account/<account-id>), or an exact principal id.
Statement resources default to this topic’s CRN; *, the exact CRN,
or this topic’s CRN followed by /* are accepted. The subtree
matches subscriptions only; list both exact and subtree resources
to cover the topic and its descendants. Owner-only.
curl --request PUT \
--url https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"document": {}
}'import requests
url = "https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy"
payload = { "document": {} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({document: {}})
};
fetch('https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy', 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://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'document' => [
]
]),
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://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy"
payload := strings.NewReader("{\n \"document\": {}\n}")
req, _ := http.NewRequest("PUT", 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.put("https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"document\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://notifications.{region}.basaltic.sh/v1/topics/{topic_id}/policy")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"document\": {}\n}"
response = http.request(request)
puts response.read_body{
"document": {}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}notifications:PutTopicPolicy. See NOTIFICATIONS permissions for the full list, what each one covers, and an example policy.Authorizations
An OAuth 2.0 bearer token, sent as Authorization: Bearer <token>.
This is the recommended way to authenticate.
Get one by exchanging a service account's access key pair at
POST /v1/oauth/token with grant_type=client_credentials. It is the
standard client-credentials grant, so any OAuth-aware library will
obtain and refresh it for you.
curl -s -u "$KEY_ID:$SECRET" -d grant_type=client_credentials \
https://iam.basaltic.sh/v1/oauth/token
Tokens last an hour by default. The same access key pair is separately your AWS SigV4 credential for the S3-compatible object endpoint, which speaks nothing else.
Path Parameters
"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
Body
pkg/policy.PolicyDocument serialization, the same engine and statement shape as bucket policies. Declared opaque here so the spec doesn't track schema changes inside the policy engine.
Response
The stored policy (statement resources canonicalised).
pkg/policy.PolicyDocument serialization, the same engine and statement shape as bucket policies. Declared opaque here so the spec doesn't track schema changes inside the policy engine.

