curl --request PATCH \
--url https://app-api.costory.io/reports/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Weekly cloud cost digest",
"description": "Top movers across our AWS + GCP spend",
"type": "PRIVATE",
"context": {
"metricId": "cost",
"groupBy": "provider",
"datePreset": "TRAILING_90_DAYS",
"currency": "USD"
},
"scheduledPeriod": "WEEKLY",
"scheduledWeekday": 1,
"status": "ACTIVE",
"widgets": [
{
"type": "TEXT",
"contentMarkdown": "## Weekly summary"
}
],
"destinations": [
{
"destinationType": "SLACK",
"destinationValues": [
"C0123456789"
]
},
{
"destinationType": "EMAIL",
"destinationValues": [
"finance@acme.com"
]
}
]
}
'import requests
url = "https://app-api.costory.io/reports/{id}"
payload = {
"name": "Weekly cloud cost digest",
"description": "Top movers across our AWS + GCP spend",
"type": "PRIVATE",
"context": {
"metricId": "cost",
"groupBy": "provider",
"datePreset": "TRAILING_90_DAYS",
"currency": "USD"
},
"scheduledPeriod": "WEEKLY",
"scheduledWeekday": 1,
"status": "ACTIVE",
"widgets": [
{
"type": "TEXT",
"contentMarkdown": "## Weekly summary"
}
],
"destinations": [
{
"destinationType": "SLACK",
"destinationValues": ["C0123456789"]
},
{
"destinationType": "EMAIL",
"destinationValues": ["finance@acme.com"]
}
]
}
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({
name: 'Weekly cloud cost digest',
description: 'Top movers across our AWS + GCP spend',
type: 'PRIVATE',
context: {
metricId: 'cost',
groupBy: 'provider',
datePreset: 'TRAILING_90_DAYS',
currency: 'USD'
},
scheduledPeriod: 'WEEKLY',
scheduledWeekday: 1,
status: 'ACTIVE',
widgets: [{type: 'TEXT', contentMarkdown: '## Weekly summary'}],
destinations: [
{destinationType: 'SLACK', destinationValues: ['C0123456789']},
{destinationType: 'EMAIL', destinationValues: ['finance@acme.com']}
]
})
};
fetch('https://app-api.costory.io/reports/{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://app-api.costory.io/reports/{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([
'name' => 'Weekly cloud cost digest',
'description' => 'Top movers across our AWS + GCP spend',
'type' => 'PRIVATE',
'context' => [
'metricId' => 'cost',
'groupBy' => 'provider',
'datePreset' => 'TRAILING_90_DAYS',
'currency' => 'USD'
],
'scheduledPeriod' => 'WEEKLY',
'scheduledWeekday' => 1,
'status' => 'ACTIVE',
'widgets' => [
[
'type' => 'TEXT',
'contentMarkdown' => '## Weekly summary'
]
],
'destinations' => [
[
'destinationType' => 'SLACK',
'destinationValues' => [
'C0123456789'
]
],
[
'destinationType' => 'EMAIL',
'destinationValues' => [
'finance@acme.com'
]
]
]
]),
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://app-api.costory.io/reports/{id}"
payload := strings.NewReader("{\n \"name\": \"Weekly cloud cost digest\",\n \"description\": \"Top movers across our AWS + GCP spend\",\n \"type\": \"PRIVATE\",\n \"context\": {\n \"metricId\": \"cost\",\n \"groupBy\": \"provider\",\n \"datePreset\": \"TRAILING_90_DAYS\",\n \"currency\": \"USD\"\n },\n \"scheduledPeriod\": \"WEEKLY\",\n \"scheduledWeekday\": 1,\n \"status\": \"ACTIVE\",\n \"widgets\": [\n {\n \"type\": \"TEXT\",\n \"contentMarkdown\": \"## Weekly summary\"\n }\n ],\n \"destinations\": [\n {\n \"destinationType\": \"SLACK\",\n \"destinationValues\": [\n \"C0123456789\"\n ]\n },\n {\n \"destinationType\": \"EMAIL\",\n \"destinationValues\": [\n \"finance@acme.com\"\n ]\n }\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://app-api.costory.io/reports/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Weekly cloud cost digest\",\n \"description\": \"Top movers across our AWS + GCP spend\",\n \"type\": \"PRIVATE\",\n \"context\": {\n \"metricId\": \"cost\",\n \"groupBy\": \"provider\",\n \"datePreset\": \"TRAILING_90_DAYS\",\n \"currency\": \"USD\"\n },\n \"scheduledPeriod\": \"WEEKLY\",\n \"scheduledWeekday\": 1,\n \"status\": \"ACTIVE\",\n \"widgets\": [\n {\n \"type\": \"TEXT\",\n \"contentMarkdown\": \"## Weekly summary\"\n }\n ],\n \"destinations\": [\n {\n \"destinationType\": \"SLACK\",\n \"destinationValues\": [\n \"C0123456789\"\n ]\n },\n {\n \"destinationType\": \"EMAIL\",\n \"destinationValues\": [\n \"finance@acme.com\"\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app-api.costory.io/reports/{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 \"name\": \"Weekly cloud cost digest\",\n \"description\": \"Top movers across our AWS + GCP spend\",\n \"type\": \"PRIVATE\",\n \"context\": {\n \"metricId\": \"cost\",\n \"groupBy\": \"provider\",\n \"datePreset\": \"TRAILING_90_DAYS\",\n \"currency\": \"USD\"\n },\n \"scheduledPeriod\": \"WEEKLY\",\n \"scheduledWeekday\": 1,\n \"status\": \"ACTIVE\",\n \"widgets\": [\n {\n \"type\": \"TEXT\",\n \"contentMarkdown\": \"## Weekly summary\"\n }\n ],\n \"destinations\": [\n {\n \"destinationType\": \"SLACK\",\n \"destinationValues\": [\n \"C0123456789\"\n ]\n },\n {\n \"destinationType\": \"EMAIL\",\n \"destinationValues\": [\n \"finance@acme.com\"\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"error": "VALIDATION_ERROR",
"details": "<string>",
"reason": "<string>"
}{
"error": "<string>"
}{
"error": "FORBIDDEN"
}{
"error": "REPORT_ARCHIVED"
}Update a report
Partially updates a report; omitted fields are left unchanged. widgets and destinations, when provided, replace the existing lists wholesale. Same conditional rules as create apply: a WEEKLY cadence needs a scheduledWeekday (from this body or already stored), EMAIL destinations must be valid addresses, and a table DIGEST widget allows at most two group-by dimensions. Archived reports cannot be updated (409).
curl --request PATCH \
--url https://app-api.costory.io/reports/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Weekly cloud cost digest",
"description": "Top movers across our AWS + GCP spend",
"type": "PRIVATE",
"context": {
"metricId": "cost",
"groupBy": "provider",
"datePreset": "TRAILING_90_DAYS",
"currency": "USD"
},
"scheduledPeriod": "WEEKLY",
"scheduledWeekday": 1,
"status": "ACTIVE",
"widgets": [
{
"type": "TEXT",
"contentMarkdown": "## Weekly summary"
}
],
"destinations": [
{
"destinationType": "SLACK",
"destinationValues": [
"C0123456789"
]
},
{
"destinationType": "EMAIL",
"destinationValues": [
"finance@acme.com"
]
}
]
}
'import requests
url = "https://app-api.costory.io/reports/{id}"
payload = {
"name": "Weekly cloud cost digest",
"description": "Top movers across our AWS + GCP spend",
"type": "PRIVATE",
"context": {
"metricId": "cost",
"groupBy": "provider",
"datePreset": "TRAILING_90_DAYS",
"currency": "USD"
},
"scheduledPeriod": "WEEKLY",
"scheduledWeekday": 1,
"status": "ACTIVE",
"widgets": [
{
"type": "TEXT",
"contentMarkdown": "## Weekly summary"
}
],
"destinations": [
{
"destinationType": "SLACK",
"destinationValues": ["C0123456789"]
},
{
"destinationType": "EMAIL",
"destinationValues": ["finance@acme.com"]
}
]
}
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({
name: 'Weekly cloud cost digest',
description: 'Top movers across our AWS + GCP spend',
type: 'PRIVATE',
context: {
metricId: 'cost',
groupBy: 'provider',
datePreset: 'TRAILING_90_DAYS',
currency: 'USD'
},
scheduledPeriod: 'WEEKLY',
scheduledWeekday: 1,
status: 'ACTIVE',
widgets: [{type: 'TEXT', contentMarkdown: '## Weekly summary'}],
destinations: [
{destinationType: 'SLACK', destinationValues: ['C0123456789']},
{destinationType: 'EMAIL', destinationValues: ['finance@acme.com']}
]
})
};
fetch('https://app-api.costory.io/reports/{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://app-api.costory.io/reports/{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([
'name' => 'Weekly cloud cost digest',
'description' => 'Top movers across our AWS + GCP spend',
'type' => 'PRIVATE',
'context' => [
'metricId' => 'cost',
'groupBy' => 'provider',
'datePreset' => 'TRAILING_90_DAYS',
'currency' => 'USD'
],
'scheduledPeriod' => 'WEEKLY',
'scheduledWeekday' => 1,
'status' => 'ACTIVE',
'widgets' => [
[
'type' => 'TEXT',
'contentMarkdown' => '## Weekly summary'
]
],
'destinations' => [
[
'destinationType' => 'SLACK',
'destinationValues' => [
'C0123456789'
]
],
[
'destinationType' => 'EMAIL',
'destinationValues' => [
'finance@acme.com'
]
]
]
]),
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://app-api.costory.io/reports/{id}"
payload := strings.NewReader("{\n \"name\": \"Weekly cloud cost digest\",\n \"description\": \"Top movers across our AWS + GCP spend\",\n \"type\": \"PRIVATE\",\n \"context\": {\n \"metricId\": \"cost\",\n \"groupBy\": \"provider\",\n \"datePreset\": \"TRAILING_90_DAYS\",\n \"currency\": \"USD\"\n },\n \"scheduledPeriod\": \"WEEKLY\",\n \"scheduledWeekday\": 1,\n \"status\": \"ACTIVE\",\n \"widgets\": [\n {\n \"type\": \"TEXT\",\n \"contentMarkdown\": \"## Weekly summary\"\n }\n ],\n \"destinations\": [\n {\n \"destinationType\": \"SLACK\",\n \"destinationValues\": [\n \"C0123456789\"\n ]\n },\n {\n \"destinationType\": \"EMAIL\",\n \"destinationValues\": [\n \"finance@acme.com\"\n ]\n }\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://app-api.costory.io/reports/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Weekly cloud cost digest\",\n \"description\": \"Top movers across our AWS + GCP spend\",\n \"type\": \"PRIVATE\",\n \"context\": {\n \"metricId\": \"cost\",\n \"groupBy\": \"provider\",\n \"datePreset\": \"TRAILING_90_DAYS\",\n \"currency\": \"USD\"\n },\n \"scheduledPeriod\": \"WEEKLY\",\n \"scheduledWeekday\": 1,\n \"status\": \"ACTIVE\",\n \"widgets\": [\n {\n \"type\": \"TEXT\",\n \"contentMarkdown\": \"## Weekly summary\"\n }\n ],\n \"destinations\": [\n {\n \"destinationType\": \"SLACK\",\n \"destinationValues\": [\n \"C0123456789\"\n ]\n },\n {\n \"destinationType\": \"EMAIL\",\n \"destinationValues\": [\n \"finance@acme.com\"\n ]\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app-api.costory.io/reports/{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 \"name\": \"Weekly cloud cost digest\",\n \"description\": \"Top movers across our AWS + GCP spend\",\n \"type\": \"PRIVATE\",\n \"context\": {\n \"metricId\": \"cost\",\n \"groupBy\": \"provider\",\n \"datePreset\": \"TRAILING_90_DAYS\",\n \"currency\": \"USD\"\n },\n \"scheduledPeriod\": \"WEEKLY\",\n \"scheduledWeekday\": 1,\n \"status\": \"ACTIVE\",\n \"widgets\": [\n {\n \"type\": \"TEXT\",\n \"contentMarkdown\": \"## Weekly summary\"\n }\n ],\n \"destinations\": [\n {\n \"destinationType\": \"SLACK\",\n \"destinationValues\": [\n \"C0123456789\"\n ]\n },\n {\n \"destinationType\": \"EMAIL\",\n \"destinationValues\": [\n \"finance@acme.com\"\n ]\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"error": "VALIDATION_ERROR",
"details": "<string>",
"reason": "<string>"
}{
"error": "<string>"
}{
"error": "FORBIDDEN"
}{
"error": "REPORT_ARCHIVED"
}Authorizations
Send Authorization: Bearer <credential> using either a Clerk session JWT or a Clerk API key (ak_*). API keys may identify a user (user_*) or organization (org_*) principal and are generated in the Clerk Dashboard under API keys.
Path Parameters
Body
Optional name patch.
Optional description patch.
PRIVATE, PUBLIC, TEMPLATE Show child attributes
Show child attributes
Delivery cadence, or null for an on-demand report. Switching to WEEKLY requires a scheduledWeekday (in this body or already stored).
DAILY, WEEKDAYS, WEEKLY, MONTHLY, null Day of week for WEEKLY reports: 0 = Sunday … 6 = Saturday. Only validated when present in the body.
ACTIVE, INACTIVE One report widget. The type field selects the shape: TOP_FLOP | GRAPH_SNAPSHOT | DASHBOARD_PDF | DIGEST | TEXT. All fields other than type depend on the chosen type.
- Option 1
- Option 2
- Option 3
- Option 4
- Option 5
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Response
Report updated
Was this page helpful?
