GTM Profile
curl --request GET \
--url https://api.opennous.cloud/v2/workspace/facts \
--header 'Content-Type: application/json' \
--data '
{
"section": "<string>",
"content": "<string>",
"mode": "<string>",
"supersedes": "<string>"
}
'import requests
url = "https://api.opennous.cloud/v2/workspace/facts"
payload = {
"section": "<string>",
"content": "<string>",
"mode": "<string>",
"supersedes": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.get(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
section: '<string>',
content: '<string>',
mode: '<string>',
supersedes: '<string>'
})
};
fetch('https://api.opennous.cloud/v2/workspace/facts', 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.opennous.cloud/v2/workspace/facts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_POSTFIELDS => json_encode([
'section' => '<string>',
'content' => '<string>',
'mode' => '<string>',
'supersedes' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"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.opennous.cloud/v2/workspace/facts"
payload := strings.NewReader("{\n \"section\": \"<string>\",\n \"content\": \"<string>\",\n \"mode\": \"<string>\",\n \"supersedes\": \"<string>\"\n}")
req, _ := http.NewRequest("GET", url, payload)
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.get("https://api.opennous.cloud/v2/workspace/facts")
.header("Content-Type", "application/json")
.body("{\n \"section\": \"<string>\",\n \"content\": \"<string>\",\n \"mode\": \"<string>\",\n \"supersedes\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.opennous.cloud/v2/workspace/facts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"section\": \"<string>\",\n \"content\": \"<string>\",\n \"mode\": \"<string>\",\n \"supersedes\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyWorkspace
GTM Profile
The user’s own GTM profile — ICP, target market, product, pricing, competitors. Workspace-level, not per-entity.
GET
/
v2
/
workspace
/
facts
GTM Profile
curl --request GET \
--url https://api.opennous.cloud/v2/workspace/facts \
--header 'Content-Type: application/json' \
--data '
{
"section": "<string>",
"content": "<string>",
"mode": "<string>",
"supersedes": "<string>"
}
'import requests
url = "https://api.opennous.cloud/v2/workspace/facts"
payload = {
"section": "<string>",
"content": "<string>",
"mode": "<string>",
"supersedes": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.get(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
section: '<string>',
content: '<string>',
mode: '<string>',
supersedes: '<string>'
})
};
fetch('https://api.opennous.cloud/v2/workspace/facts', 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.opennous.cloud/v2/workspace/facts",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_POSTFIELDS => json_encode([
'section' => '<string>',
'content' => '<string>',
'mode' => '<string>',
'supersedes' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"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.opennous.cloud/v2/workspace/facts"
payload := strings.NewReader("{\n \"section\": \"<string>\",\n \"content\": \"<string>\",\n \"mode\": \"<string>\",\n \"supersedes\": \"<string>\"\n}")
req, _ := http.NewRequest("GET", url, payload)
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.get("https://api.opennous.cloud/v2/workspace/facts")
.header("Content-Type", "application/json")
.body("{\n \"section\": \"<string>\",\n \"content\": \"<string>\",\n \"mode\": \"<string>\",\n \"supersedes\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.opennous.cloud/v2/workspace/facts")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"section\": \"<string>\",\n \"content\": \"<string>\",\n \"mode\": \"<string>\",\n \"supersedes\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyWhere the per-entity endpoints (
/v2/accounts/:id, /v2/context) return facts about people and companies, this returns the workspace owner’s own GTM profile — what they sell, who they sell to, pricing, and positioning — the context an agent should reference when answering questions like “what’s our ICP?” or “what’s our pricing?”
Request
curl 'https://api.opennous.cloud/v2/workspace/facts?categories=ICP,Market&limit=20' \
-H 'Authorization: Bearer YOUR_API_KEY'
Query params
string
Comma-separated list to filter (e.g.
ICP,Pricing). Omit to return all categories.Common categories: ICP, Market, Product, Pricing, Competitors, Playbook. Users can add any custom category in the in-app GTM Context tab.number
default:"50"
Max facts to return. Cap 500.
Response
{
"facts": [
{
"id": "7e2bd11f-...",
"category": "ICP",
"content": "GTM Engineers or RevOps leaders at B2B SaaS, 50-200 employees, US.",
"source": "manual",
"recorded_at": "2026-05-24T16:37:54Z"
},
{
"id": "aec9de1c-...",
"category": "Pricing",
"content": "Free self-host. Scale $99/mo. Agency $499/mo.",
"source": "manual",
"recorded_at": "2026-05-20T11:02:00Z"
}
],
"count": 2,
"by_category": { "ICP": 1, "Pricing": 1 }
}
When to call it
- “What’s our ICP?” —
categories=["ICP"] - “What’s our pricing strategy?” —
categories=["Pricing"] - “What differentiates us from competitors?” —
categories=["Competitors","Product"] - “Show me the whole playbook” — no
categoriesfilter
/v2/context) AND the user’s GTM profile (/v2/workspace/facts). The GTM profile tells it how YOU sell; the context tells it about THEM. Combine for natural copy.
Writing back
POST to the same path to keep a section of the GTM context current. Each section is a living file: in the default replace mode the new content evolves that section’s belief — the prior version is kept as history, never silently contradicted — so you just write the section’s current state. This is the endpoint behind the MCP set_workspace_profile tool.
curl -X POST https://api.opennous.cloud/v2/workspace/facts \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"section": "Pricing",
"content": "Free self-host. Scale $149/mo. Agency $599/mo.",
"mode": "replace"
}'
string
required
One of
ICP, Market, Product, Pricing, Competitors, Positioning (these feed the ICP scoring model), GTM Motion, or Notes.string
required
The section’s current content — one short, current statement, not an essay.
string
default:"replace"
replace evolves the section and keeps the prior version as history. append logs a new entry without replacing — the default for Notes.string
Explicit fact id to replace (overrides section matching).
{
"fact": { "id": "b8f0...", "category": "Pricing", "content": "Free self-host. Scale $149/mo. Agency $599/mo." },
"section": "Pricing",
"mode": "replace",
"superseded": true
}
How it gets there
The GTM profile is built through the in-app GTM Context tab (the guided Playbook setup, or added directly), through thePOST write-back above, or via POST /v2/observations with a note.<uuid> property on the workspace entity. All write paths produce the same asserted-claim records this endpoint reads.