Save card as widget template
curl --request POST \
--url https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Done tasks per hub",
"description": "Saved from the Jakarta Hub - Daily dashboard."
}
'import requests
url = "https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template"
payload = {
"name": "Done tasks per hub",
"description": "Saved from the Jakarta Hub - Daily dashboard."
}
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({
name: 'Done tasks per hub',
description: 'Saved from the Jakarta Hub - Daily dashboard.'
})
};
fetch('https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template', 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://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template",
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([
'name' => 'Done tasks per hub',
'description' => 'Saved from the Jakarta Hub - Daily dashboard.'
]),
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://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template"
payload := strings.NewReader("{\n \"name\": \"Done tasks per hub\",\n \"description\": \"Saved from the Jakarta Hub - Daily dashboard.\"\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://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Done tasks per hub\",\n \"description\": \"Saved from the Jakarta Hub - Daily dashboard.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template")
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 \"name\": \"Done tasks per hub\",\n \"description\": \"Saved from the Jakarta Hub - Daily dashboard.\"\n}"
response = http.request(request)
puts response.read_body{
"status": true,
"code": 201,
"message": "Widget has been added successfully.",
"data": {
"_id": "66fcd2a1e4b0a7d3c1f20c02",
"organizationId": "6650c2a1f3b9e4001c7d2a10",
"schemaVersion": 1,
"name": "Done tasks per hub",
"description": "Saved from the Jakarta Hub - Daily dashboard.",
"category": "custom",
"viz": "bar",
"spec": {
"specVersion": 1,
"dataSourceId": "task",
"timeField": "doneTime",
"measures": [
{
"id": "m1",
"fn": "count"
}
],
"dimensions": [
{
"id": "d1",
"kind": "terms",
"field": "hubName",
"limit": 10
}
],
"filters": [
{
"id": "f1",
"field": "status",
"operator": "eq",
"value": "DONE"
}
]
},
"composite": null,
"content": null,
"defaultLayout": {
"w": 6,
"h": 6
},
"isCustom": true,
"createdBy": "[email protected]",
"updatedBy": "[email protected]",
"createdTime": "2026-10-13T03:00:00.000000Z",
"updatedTime": "2026-10-13T03:00:00.000000Z"
}
}{
"status": false,
"message": "Only a custom query widget can be saved as a widget template; this widget is text.",
"failedCode": "dydsh-014"
}{
"status": false,
"message": "Unauthenticated.",
"failedCode": "auth-034"
}{
"status": false,
"message": "Access denied. You do not have permission for add dashboard. Please contact your admin to request access.",
"failedCode": "sys-035"
}{
"status": false,
"code": 404,
"message": "This card no longer exists on the dashboard.",
"data": [],
"failedCode": "dydsh-042"
}{
"status": false,
"code": 422,
"message": "This dashboard was saved by a newer version of MileApp and cannot be opened here. Please refresh the page and try again.",
"data": [],
"failedCode": "dydsh-040"
}{
"status": false,
"code": 500,
"message": "something_wrong",
"failedCode": "dydsh-045"
}Dashboard
Save card as widget template
View-mode route. Copies one card of a dashboard the caller can see into a new widget template of the caller’s organization: the card’s viz, spec and defaultLayout are copied, name and description come from the body, and the server sets isCustom: true and category: custom. The card and the dashboard are not changed. Only a custom query card can be saved. The stored spec keeps its Task type unchanged, so the Task type is not checked again. In edit mode the app sends the draft card’s content to Create custom widget (POST /dynamic-dashboard-widget) instead, without saving the dashboard.
POST
/
dynamic-dashboard
/
{id}
/
card
/
{cardId}
/
save-as-widget-template
Save card as widget template
curl --request POST \
--url https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"name": "Done tasks per hub",
"description": "Saved from the Jakarta Hub - Daily dashboard."
}
'import requests
url = "https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template"
payload = {
"name": "Done tasks per hub",
"description": "Saved from the Jakarta Hub - Daily dashboard."
}
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({
name: 'Done tasks per hub',
description: 'Saved from the Jakarta Hub - Daily dashboard.'
})
};
fetch('https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template', 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://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template",
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([
'name' => 'Done tasks per hub',
'description' => 'Saved from the Jakarta Hub - Daily dashboard.'
]),
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://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template"
payload := strings.NewReader("{\n \"name\": \"Done tasks per hub\",\n \"description\": \"Saved from the Jakarta Hub - Daily dashboard.\"\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://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"name\": \"Done tasks per hub\",\n \"description\": \"Saved from the Jakarta Hub - Daily dashboard.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://apiweb.mile.app/api/v3/dynamic-dashboard/{id}/card/{cardId}/save-as-widget-template")
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 \"name\": \"Done tasks per hub\",\n \"description\": \"Saved from the Jakarta Hub - Daily dashboard.\"\n}"
response = http.request(request)
puts response.read_body{
"status": true,
"code": 201,
"message": "Widget has been added successfully.",
"data": {
"_id": "66fcd2a1e4b0a7d3c1f20c02",
"organizationId": "6650c2a1f3b9e4001c7d2a10",
"schemaVersion": 1,
"name": "Done tasks per hub",
"description": "Saved from the Jakarta Hub - Daily dashboard.",
"category": "custom",
"viz": "bar",
"spec": {
"specVersion": 1,
"dataSourceId": "task",
"timeField": "doneTime",
"measures": [
{
"id": "m1",
"fn": "count"
}
],
"dimensions": [
{
"id": "d1",
"kind": "terms",
"field": "hubName",
"limit": 10
}
],
"filters": [
{
"id": "f1",
"field": "status",
"operator": "eq",
"value": "DONE"
}
]
},
"composite": null,
"content": null,
"defaultLayout": {
"w": 6,
"h": 6
},
"isCustom": true,
"createdBy": "[email protected]",
"updatedBy": "[email protected]",
"createdTime": "2026-10-13T03:00:00.000000Z",
"updatedTime": "2026-10-13T03:00:00.000000Z"
}
}{
"status": false,
"message": "Only a custom query widget can be saved as a widget template; this widget is text.",
"failedCode": "dydsh-014"
}{
"status": false,
"message": "Unauthenticated.",
"failedCode": "auth-034"
}{
"status": false,
"message": "Access denied. You do not have permission for add dashboard. Please contact your admin to request access.",
"failedCode": "sys-035"
}{
"status": false,
"code": 404,
"message": "This card no longer exists on the dashboard.",
"data": [],
"failedCode": "dydsh-042"
}{
"status": false,
"code": 422,
"message": "This dashboard was saved by a newer version of MileApp and cannot be opened here. Please refresh the page and try again.",
"data": [],
"failedCode": "dydsh-040"
}{
"status": false,
"code": 500,
"message": "something_wrong",
"failedCode": "dydsh-045"
}Authorizations
Use a valid Bearer token to authenticate.
Path Parameters
Source dashboard _id
The card's cardId in the stored dashboard's widgets[]
Body
application/json
Widget template name and description