ax-check.com
by Gauge
F
Front
front.com
ax-check.com
Checked 13 October 2026
B
84/100
Agents need your login
Front's docs and pricing are clear, but only 1 of 3 agent runs finished.
Quickstarts, API reference, and MCP docs are solid (19 of 23 checks pass), and pricing is public: Starter $25, Professional $65, Enterprise $105 per seat/mo.
2 fixes to start with
Concrete changes, backed by what we found.
Recorded coding sessions
Same task, 3 models, no front.com account. Recorded 13 October 2026 on Pi.
3 recorded · 2m 44s
2m 44s · recorded
Session findings
Select a finding to see it in context.
›Thinking…
Let me explore the repo to see what's there and figure out what "Front" is — Front is the shared inbox/customer communication platform (frontapp.com). They have a REST API and SDKs.
Let me check the working directory first.
ls -la /sandbox/repo && cat /sandbox/repo/README* 2>/dev/null | head -50
total 16
total 16 drwxr-xr-x 3 root root 4096 Sep 18 08:00 . drwxr-xr-x 7 root root 4096 Oct 13 20:19 .. drwxr-xr-x 8 root root 4096 Sep 24 20:05 .git -rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore
Recorded tool call
{
"type": "tool_call",
"seq": 3,
"ts": "2026-10-13T20:19:54.665Z",
"name": "bash",
"turn": 1,
"input": {
"command": "ls -la /sandbox/repo && cat /sandbox/repo/README* 2>/dev/null | head -50"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_375cf94ad50643b0b8866ed6",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 5,
"ts": "2026-10-13T20:19:54.665Z",
"turn": 1,
"output": {
"content": [
{
"text": "total 16\ndrwxr-xr-x 3 root root 4096 Sep 18 08:00 .\ndrwxr-xr-x 7 root root 4096 Oct 13 20:19 ..\ndrwxr-xr-x 8 root root 4096 Sep 24 20:05 .git\n-rw-r--r-- 1 root root 408 Sep 18 08:00 .gitignore\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_375cf94ad50643b0b8866ed6",
"is_error": false,
"tool_kind": "shell"
}env | grep -iE 'front|api|token|key' | sed 's/=.*/=<redacted-present>/'; echo "---"; node --version 2>/dev/null; python3 --version 2>/dev/null
PI_GATEWAY_API_KEY=<redacted-present>
PI_GATEWAY_API_KEY=<redacted-present> GIT_CONFIG_KEY_0=<redacted-present> --- v22.23.2 Python 3.12.3
Recorded tool call
{
"type": "tool_call",
"seq": 4,
"ts": "2026-10-13T20:19:54.665Z",
"name": "bash",
"turn": 1,
"input": {
"command": "env | grep -iE 'front|api|token|key' | sed 's/=.*/=<redacted-present>/'; echo \"---\"; node --version 2>/dev/null; python3 --version 2>/dev/null"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_66cb39222d244dc3a8bf85c0",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 6,
"ts": "2026-10-13T20:19:54.665Z",
"turn": 1,
"output": {
"content": [
{
"text": "PI_GATEWAY_API_KEY=<redacted-present>\nGIT_CONFIG_KEY_0=<redacted-present>\n---\nv22.23.2\nPython 3.12.3\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_66cb39222d244dc3a8bf85c0",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
The repo is empty. "Front" is the shared-inbox/customer operations platform (frontapp.com). It has a hosted REST API (api2.frontapp.com) with API tokens, plus an official JS SDK (@frontapp/front-core / frontapp-api-client?). The official SDK is @frontapp/front-core? Actually the official Front SDK for Node is frontapp (npm package "frontapp"). There's also the Plugin SDK for UI plugins. The Core API is REST with token auth.
I don't have a Front API token. Without credentials, I can't actually hit the hosted API. But I can still build a simple example that uses the API via token, and explain pricing. I should be honest that I got blocked at actually calling the API due to missing credentials — the user said "Let me know if you get blocked."
Let me check whether there's a token available anywhere. No FRONT env vars. So I'll build the example code (Node script using REST API or the SDK), attempt a lightweight call which will fail due to no credentials, and report.
Pricing (as of my knowledge): Front sells per-seat pricing: Starter ~$19/seat/mo, Growth ~$59, Scale ~$99, Premier ~$229 (annual billing). Free trial 7 days. API access is included on plans; Core API rate limits per plan tier. I should caveat pricing may have changed and to check frontapp.com/pricing. I don't have web access? Let me check if I can curl the pricing page quickly — that could verify. Quick curl with timeout is fine.
Ease of management: Front is a hosted SaaS, well-documented REST API, webhooks, SDKs. Easy for an agent to manage via API.
Let me do a quick curl to the API to show behavior without token, and try to fetch pricing page.
curl -s -m 15 -o /dev/null -w "%{http_code}\n" https://api2.frontapp.com/me; curl -s -m 15 https://api2.frontapp.com/me | head -c 300; echo401
401
{"_error":{"status":401,"title":"Unauthenticated","message":"JSON Web Token error"}}
Recorded tool call
{
"type": "tool_call",
"seq": 9,
"ts": "2026-10-13T20:20:13.003Z",
"name": "bash",
"turn": 1,
"input": {
"command": "curl -s -m 15 -o /dev/null -w \"%{http_code}\\n\" https://api2.frontapp.com/me; curl -s -m 15 https://api2.frontapp.com/me | head -c 300; echo"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_5b6c3d939db44e7ba8ba84db",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 13,
"ts": "2026-10-13T20:20:14.307Z",
"turn": 1,
"output": {
"content": [
{
"text": "401\n{\"_error\":{\"status\":401,\"title\":\"Unauthenticated\",\"message\":\"JSON Web Token error\"}}\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_5b6c3d939db44e7ba8ba84db",
"is_error": false,
"tool_kind": "shell"
}curl -s -m 15 https://front.com/pricing -o /tmp/pricing.html -w "%{http_code}\n" 2>&1; grep -oiE '\$[0-9]+(/seat)?[^<]{0,40}' /tmp/pricing.html 2>/dev/null | sort -u | head -20200
200
$0.05
$0.05\",\"description\":\"Understands inqu
$0.05\",\"priceDescription\":\"/conversati
$0.39\",\"description\":\"Gathers more con
$0.89\",\"description\":\"Fully resolves t
$105
$105\",\"monthlyPrice\":\"Only available on
$10\"}\ne:[\"$\",\"span\",null,\"$f\"]\n1f:
$11\"]\nf:{\"className\":\"bg-citron-500 ro
$12K. Reach out to
$12K. Reach out to \",[\"$\",\"a\",null,{\"
$1f\",\"fill\":\"currentColor\"}]}],\"subt
$20
$200
$200\",\"priceDescription\":\"per 100 API re
$20\",\"fill\":\"currentColor\"}],[\"$\",\"
$20\",\"priceDescription\":[\"/ seat / mont
$21\",\"fill\":\"currentColor\"}]}]},{\"tit
$22\",\"fill\":\"currentColor\"}],[\"$\",\"
$24\",[\"$\",\"$L23\",null,{\"id\":\"optimi
Recorded tool call
{
"type": "tool_call",
"seq": 11,
"ts": "2026-10-13T20:20:13.003Z",
"name": "bash",
"turn": 1,
"input": {
"command": "curl -s -m 15 https://front.com/pricing -o /tmp/pricing.html -w \"%{http_code}\\n\" 2>&1; grep -oiE '\\$[0-9]+(/seat)?[^<]{0,40}' /tmp/pricing.html 2>/dev/null | sort -u | head -20"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_31332ffd5ade4fad916b2c17",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 14,
"ts": "2026-10-13T20:20:15.731Z",
"turn": 1,
"output": {
"content": [
{
"text": "200\n$0.05\n$0.05\\\",\\\"description\\\":\\\"Understands inqu\n$0.05\\\",\\\"priceDescription\\\":\\\"/conversati\n$0.39\\\",\\\"description\\\":\\\"Gathers more con\n$0.89\\\",\\\"description\\\":\\\"Fully resolves t\n$105\n$105\\\",\\\"monthlyPrice\\\":\\\"Only available on \n$10\\\"}\\ne:[\\\"$\\\",\\\"span\\\",null,\\\"$f\\\"]\\n1f:\n$11\\\"]\\nf:{\\\"className\\\":\\\"bg-citron-500 ro\n$12K. Reach out to \n$12K. Reach out to \\\",[\\\"$\\\",\\\"a\\\",null,{\\\"\n$1f\\\",\\\"fill\\\":\\\"currentColor\\\"}]}],\\\"subt\n$20\n$200\n$200\\\",\\\"priceDescription\\\":\\\"per 100 API re\n$20\\\",\\\"fill\\\":\\\"currentColor\\\"}],[\\\"$\\\",\\\"\n$20\\\",\\\"priceDescription\\\":[\\\"/ seat / mont\n$21\\\",\\\"fill\\\":\\\"currentColor\\\"}]}]},{\\\"tit\n$22\\\",\\\"fill\\\":\\\"currentColor\\\"}],[\\\"$\\\",\\\"\n$24\\\",[\\\"$\\\",\\\"$L23\\\",null,{\\\"id\\\":\\\"optimi\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_31332ffd5ade4fad916b2c17",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
The pricing page fetched. Let me extract more plan names and details. Let me grep for plan names like "Starter", "Growth", "Scale", "Premier" and seat prices.
grep -oiE '"(title|name)":"(Starter|Growth|Scale|Premier|Free|Essentials)[^"]*"' /tmp/pricing.html | sort -u | head; echo "---"; grep -oE '\$[0-9]+\",\"priceDescription\":\"[^\"]{0,60}' /tmp/pricing.html | sort -u | head -20; echo "---"; grep -oiE '(starter|growth|scale|premier)[^,]{0,80}' /tmp/pricing.html | sort -u | head -10---
--- --- STARTER Starter Starter and Professional<br/>Included in Enterprise</span></div><button class="flex fon Starter and Professional\" Starter plan customers will have non-removable Front branding on their knowledge base f Starter plan only supports a single channel type of Email Starter plan will have non-removable Front branding on their chat widget.\"}] Starter plan?</div><div class="flex"><svg width="32" height="32" viewBox="0 0 32 32" cl Starter plan?\" Starter</div><div class="bg-white rounded-t-[24px] text-caption1 md:text-h4 text-blue-9
Recorded tool call
{
"type": "tool_call",
"seq": 17,
"ts": "2026-10-13T20:20:21.831Z",
"name": "bash",
"turn": 1,
"input": {
"command": "grep -oiE '\"(title|name)\":\"(Starter|Growth|Scale|Premier|Free|Essentials)[^\"]*\"' /tmp/pricing.html | sort -u | head; echo \"---\"; grep -oE '\\$[0-9]+\\\",\\\"priceDescription\\\":\\\"[^\\\"]{0,60}' /tmp/pricing.html | sort -u | head -20; echo \"---\"; grep -oiE '(starter|growth|scale|premier)[^,]{0,80}' /tmp/pricing.html | sort -u | head -10"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_e6a5330eedf24ab38e2af70f",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 18,
"ts": "2026-10-13T20:20:21.831Z",
"turn": 1,
"output": {
"content": [
{
"text": "---\n---\nSTARTER\nStarter\nStarter and Professional<br/>Included in Enterprise</span></div><button class=\"flex fon\nStarter and Professional\\\"\nStarter plan customers will have non-removable Front branding on their knowledge base f\nStarter plan only supports a single channel type of Email\nStarter plan will have non-removable Front branding on their chat widget.\\\"}]\nStarter plan?</div><div class=\"flex\"><svg width=\"32\" height=\"32\" viewBox=\"0 0 32 32\" cl\nStarter plan?\\\"\nStarter</div><div class=\"bg-white rounded-t-[24px] text-caption1 md:text-h4 text-blue-9\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_e6a5330eedf24ab38e2af70f",
"is_error": false,
"tool_kind": "shell"
}grep -oE 'Professional|Enterprise|per seat / month|/ seat / mont[a-z]*|free trial|[0-9]+-day' /tmp/pricing.html | sort -u | head -15; echo "---"; grep -oE 'plan[^"]{0,3}(Starter|Professional|Enterprise)' /tmp/pricing.html | sort -u | head; echo "---"; grep -oE '\$[0-9]+","[a-zA-Z]+[Pp]rice[^,]{0,50}' /tmp/pricing.html | sort -u | head/ seat / month
/ seat / month 14-day Enterprise Professional free trial --- ---
Recorded tool call
{
"type": "tool_call",
"seq": 20,
"ts": "2026-10-13T20:20:26.968Z",
"name": "bash",
"turn": 1,
"input": {
"command": "grep -oE 'Professional|Enterprise|per seat / month|/ seat / mont[a-z]*|free trial|[0-9]+-day' /tmp/pricing.html | sort -u | head -15; echo \"---\"; grep -oE 'plan[^\"]{0,3}(Starter|Professional|Enterprise)' /tmp/pricing.html | sort -u | head; echo \"---\"; grep -oE '\\$[0-9]+\",\"[a-zA-Z]+[Pp]rice[^,]{0,50}' /tmp/pricing.html | sort -u | head"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_1dd9acf072914fdca3a51cac",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 21,
"ts": "2026-10-13T20:20:27.292Z",
"turn": 1,
"output": {
"content": [
{
"text": "/ seat / month\n14-day\nEnterprise\nProfessional\nfree trial\n---\n---\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_1dd9acf072914fdca3a51cac",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Let me get the plan tiers and their prices more precisely. Search for plan title blocks with prices.
python3 - <<'EOF'
import re
html = open('/tmp/pricing.html', encoding='utf-8', errors='ignore').read()
# find plan names near prices
for m in re.finditer(r'(Starter|Professional|Enterprise|Growth|Scale|Premier)', html):
seg = html[m.start():m.start()+400]
prices = re.findall(r'\$\d+', seg)
if prices:
print(m.group(1), '->', prices[:3])
EOFStarter -> ['$25']
Starter -> ['$25'] Professional -> ['$65'] Enterprise -> ['$105'] Professional -> ['$25'] Enterprise -> ['$25'] Starter -> ['$25', '$35'] Professional -> ['$65', '$85'] Enterprise -> ['$105'] Professional -> ['$200'] Enterprise -> ['$200'] Starter -> ['$8', '$8'] Starter -> ['$8', '$8', '$8']
Recorded tool call
{
"type": "tool_call",
"seq": 24,
"ts": "2026-10-13T20:20:34.248Z",
"name": "bash",
"turn": 1,
"input": {
"command": "python3 - <<'EOF'\nimport re\nhtml = open('/tmp/pricing.html', encoding='utf-8', errors='ignore').read()\n# find plan names near prices\nfor m in re.finditer(r'(Starter|Professional|Enterprise|Growth|Scale|Premier)', html):\n seg = html[m.start():m.start()+400]\n prices = re.findall(r'\\$\\d+', seg)\n if prices:\n print(m.group(1), '->', prices[:3])\nEOF"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_73a423ea92ae490689c7f0ca",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 25,
"ts": "2026-10-13T20:20:34.570Z",
"turn": 1,
"output": {
"content": [
{
"text": "Starter -> ['$25']\nProfessional -> ['$65']\nEnterprise -> ['$105']\nProfessional -> ['$25']\nEnterprise -> ['$25']\nStarter -> ['$25', '$35']\nProfessional -> ['$65', '$85']\nEnterprise -> ['$105']\nProfessional -> ['$200']\nEnterprise -> ['$200']\nStarter -> ['$8', '$8']\nStarter -> ['$8', '$8', '$8']\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_73a423ea92ae490689c7f0ca",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Good — current pricing: Starter $25/seat/mo (annual) / $35 monthly, Professional $65 / $85, Enterprise $105 (annual only). 14-day free trial. AI add-ons priced per conversation ($0.05–$0.89). API rate-limit boost $200 per 100 API requests (that was "per 100 API re..." — probably an add-on for additional API capacity).
Now build the example: a simple Node script using Front's Core API (hosted at api2.frontapp.com) with an API token — list teammates, inboxes, and create a draft/message. Use plain fetch (Node 22 has fetch) to keep it light, no local stacks. Also demonstrate the official JS SDK? The official npm package is "frontapp". Keeping it light: a single script using fetch is simplest, but the user said "through its SDK or API" — API via fetch qualifies. Maybe include both: main script with fetch, note SDK option.
I'll create the example, run it (will 401 without token), and report being blocked on credentials. Also note Front has a developer workflow (Core API + webhooks + plugin SDK), so it's manageable.
Let me write files: front-example/example.mjs and README.md. Also a .env.example. Keep it small.
File edits
1 file
Writtenfront-example/example.mjsView changes
/sandbox/repo/front-example/example.mjs
Written content · previous contents were not recorded
// Front Core API quickstart (hosted SaaS, no local services needed).// 1. In Front: Settings > Company > Developers > Create token (API token).// 2. export FRONT_API_TOKEN=... then: node example.mjsconst TOKEN = process.env.FRONT_API_TOKEN;const BASE = 'https://api2.frontapp.com';if (!TOKEN) {console.error('Set FRONT_API_TOKEN first (Front > Settings > Developers > API Tokens).');process.exit(1);}async function api(path, options = {}) {const res = await fetch(`${BASE}${path}`, {...options,headers: {Authorization: `Bearer ${TOKEN}`,'Content-Type': 'application/json',...options.headers,},});if (!res.ok) {const body = await res.text();throw new Error(`${options.method ?? 'GET'} ${path} -> ${res.status}: ${body}`);}return res.status === 204 ? null : res.json();}// Who am I?const me = await api('/me');console.log('Authenticated as app token:', me.name ?? me.id);// List the first few inboxesconst inboxes = await api('/inboxes?limit=5');for (const inbox of inboxes._results ?? []) {console.log(`Inbox: ${inbox.name} (${inbox.id})`);}// List recent conversations in the teamconst convos = await api('/conversations?limit=5');for (const c of convos._results ?? []) {console.log(`Conversation [${c.status}] ${c.subject ?? '(no subject)'} (${c.id})`);}// Create a draft reply in the first conversation found (safe, non-sending write op)const first = convos._results?.[0];if (first) {const inbox = await api(`/conversations/${first.id}/inbox`);const draft = await api(`/conversations/${first.id}/drafts`, {method: 'POST',body: JSON.stringify({channel_id: undefined, // not needed for comment drafts; see belowbody: 'Hello from the Front Core API quickstart (draft, not sent).',mode: 'private', // private comment draft, never emailed to the customer}),});console.log('Created draft comment:', draft.id ?? draft);}
Source: write · call_f7025653860a45668bdeae68
Recorded tool call
{
"type": "tool_call",
"seq": 28,
"ts": "2026-10-13T20:20:59.807Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/front-example/example.mjs",
"content": "// Front Core API quickstart (hosted SaaS, no local services needed).\n// 1. In Front: Settings > Company > Developers > Create token (API token).\n// 2. export FRONT_API_TOKEN=... then: node example.mjs\n\nconst TOKEN = process.env.FRONT_API_TOKEN;\nconst BASE = 'https://api2.frontapp.com';\n\nif (!TOKEN) {\n console.error('Set FRONT_API_TOKEN first (Front > Settings > Developers > API Tokens).');\n process.exit(1);\n}\n\nasync function api(path, options = {}) {\n const res = await fetch(`${BASE}${path}`, {\n ...options,\n headers: {\n Authorization: `Bearer ${TOKEN}`,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n if (!res.ok) {\n const body = await res.text();\n throw new Error(`${options.method ?? 'GET'} ${path} -> ${res.status}: ${body}`);\n }\n return res.status === 204 ? null : res.json();\n}\n\n// Who am I?\nconst me = await api('/me');\nconsole.log('Authenticated as app token:', me.name ?? me.id);\n\n// List the first few inboxes\nconst inboxes = await api('/inboxes?limit=5');\nfor (const inbox of inboxes._results ?? []) {\n console.log(`Inbox: ${inbox.name} (${inbox.id})`);\n}\n\n// List recent conversations in the team\nconst convos = await api('/conversations?limit=5');\nfor (const c of convos._results ?? []) {\n console.log(`Conversation [${c.status}] ${c.subject ?? '(no subject)'} (${c.id})`);\n}\n\n// Create a draft reply in the first conversation found (safe, non-sending write op)\nconst first = convos._results?.[0];\nif (first) {\n const inbox = await api(`/conversations/${first.id}/inbox`);\n const draft = await api(`/conversations/${first.id}/drafts`, {\n method: 'POST',\n body: JSON.stringify({\n channel_id: undefined, // not needed for comment drafts; see below\n body: 'Hello from the Front Core API quickstart (draft, not sent).',\n mode: 'private', // private comment draft, never emailed to the customer\n }),\n });\n console.log('Created draft comment:', draft.id ?? draft);\n}\n"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_f7025653860a45668bdeae68",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 29,
"ts": "2026-10-13T20:20:59.807Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 1969 bytes to /sandbox/repo/front-example/example.mjs",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_f7025653860a45668bdeae68",
"is_error": false,
"tool_kind": "file_edit"
}File edits
1 file
Writtenfront-example/README.mdView changes
/sandbox/repo/front-example/README.md
Written content · previous contents were not recorded
# Front Core API quickstartFront (front.com) is a hosted shared-inbox / customer operations platform. Everything hereruns against its hosted REST API — no local services to start.## Get a token1. Log into Front as an admin.2. **Settings → Company → Developers → API Tokens → Create token**, pick scopes(Shared resources / Team resources as needed).3. `export FRONT_API_TOKEN=...`## Run```shnode example.mjs```It will:- verify auth via `GET /me`,- list inboxes and recent conversations,- create a **private draft comment** on the newest conversation (a safe, non-sending write).## Notes- Base URL: `https://api2.frontapp.com`, auth is `Authorization: Bearer <token>`.- Official JS SDK: `npm i frontapp` (wraps the same REST API); there is also a Plugin SDKfor building sidebar UI plugins inside Front, and webhooks for event-driven workflows.- Rate limits vary by plan tier; an add-on increases API throughput.
Source: write · call_53c8eee5dac94016a009bd54
Recorded tool call
{
"type": "tool_call",
"seq": 31,
"ts": "2026-10-13T20:21:11.371Z",
"name": "write",
"turn": 1,
"input": {
"path": "/sandbox/repo/front-example/README.md",
"content": "# Front Core API quickstart\n\nFront (front.com) is a hosted shared-inbox / customer operations platform. Everything here\nruns against its hosted REST API — no local services to start.\n\n## Get a token\n\n1. Log into Front as an admin.\n2. **Settings → Company → Developers → API Tokens → Create token**, pick scopes\n (Shared resources / Team resources as needed).\n3. `export FRONT_API_TOKEN=...`\n\n## Run\n\n```sh\nnode example.mjs\n```\n\nIt will:\n- verify auth via `GET /me`,\n- list inboxes and recent conversations,\n- create a **private draft comment** on the newest conversation (a safe, non-sending write).\n\n## Notes\n\n- Base URL: `https://api2.frontapp.com`, auth is `Authorization: Bearer <token>`.\n- Official JS SDK: `npm i frontapp` (wraps the same REST API); there is also a Plugin SDK\n for building sidebar UI plugins inside Front, and webhooks for event-driven workflows.\n- Rate limits vary by plan tier; an add-on increases API throughput.\n"
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_53c8eee5dac94016a009bd54",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 32,
"ts": "2026-10-13T20:21:11.371Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully wrote 943 bytes to /sandbox/repo/front-example/README.md",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_53c8eee5dac94016a009bd54",
"is_error": false,
"tool_kind": "file_edit"
}›Thinking…
Run it to show what happens without a token. Also fix: my draft creation code has a sloppy channel_id: undefined — that's fine in JSON.stringify (dropped). The draft endpoint for comments: POST /conversations/{id}/drafts with body and mode 'private' — actually comment drafts use POST /conversations/{conversation_id}/drafts? Front API: creating a draft message requires channel_id; creating a draft comment is POST /conversations/{id}/drafts with "mode": "comment"? Let me recall: Front Core API has "Create draft" (message draft, requires channel_id, author_id) and "Create draft comment"? There is POST /conversations/{conversation_id}/drafts to create a draft reply (needs channel_id, author_id, body), and drafts can be mode 'private' for comments. I believe mode: 'private' makes it a comment draft and channel_id isn't required. author_id may be required. Since I can't test without a token, I'll simplify: just add a comment via POST /conversations/{id}/comments with author_id. But author_id requires a teammate id. To keep the example robust without me being able to test, maybe drop the write op, or make it clearly labeled best-effort. The user wants a simple example — keep it but fetch first teammate to use as author for a comment (comments are internal, safe). POST /comments? Front API: POST /conversations/{conversation_id}/comments with {author_id, body}. That's a documented endpoint and safe (internal note). Let me update the script to do that instead — cleaner and more likely correct.
Let me fix the write operation — a private comment via the comments endpoint is simpler and well-documented:
File edits
1 file
Modifiedfront-example/example.mjs+7−7View changes
/sandbox/repo/front-example/example.mjs
Replacement excerpt
-// Create a draft reply in the first conversation found (safe, non-sending write op)+// Post an internal comment on the newest conversation (safe: never emailed to customers)const first = convos._results?.[0];if (first) {- const inbox = await api(`/conversations/${first.id}/inbox`);- const draft = await api(`/conversations/${first.id}/drafts`, {+ const teammates = await api('/teammates?limit=1');+ const author = teammates._results?.[0];+ const comment = await api(`/conversations/${first.id}/comments`, {method: 'POST',body: JSON.stringify({- channel_id: undefined, // not needed for comment drafts; see below- body: 'Hello from the Front Core API quickstart (draft, not sent).',- mode: 'private', // private comment draft, never emailed to the customer+ author_id: author.id,+ body: `Hello from the Front Core API quickstart (posted by ${author.email}).`,}),});- console.log('Created draft comment:', draft.id ?? draft);+ console.log('Posted internal comment:', comment.id);}
Source: edit · call_e490b727cbb04f3d8be1804b
Recorded tool call
{
"type": "tool_call",
"seq": 36,
"ts": "2026-10-13T20:21:31.522Z",
"name": "edit",
"turn": 1,
"input": {
"path": "/sandbox/repo/front-example/example.mjs",
"edits": [
{
"newText": "// Post an internal comment on the newest conversation (safe: never emailed to customers)\nconst first = convos._results?.[0];\nif (first) {\n const teammates = await api('/teammates?limit=1');\n const author = teammates._results?.[0];\n const comment = await api(`/conversations/${first.id}/comments`, {\n method: 'POST',\n body: JSON.stringify({\n author_id: author.id,\n body: `Hello from the Front Core API quickstart (posted by ${author.email}).`,\n }),\n });\n console.log('Posted internal comment:', comment.id);\n}",
"oldText": "// Create a draft reply in the first conversation found (safe, non-sending write op)\nconst first = convos._results?.[0];\nif (first) {\n const inbox = await api(`/conversations/${first.id}/inbox`);\n const draft = await api(`/conversations/${first.id}/drafts`, {\n method: 'POST',\n body: JSON.stringify({\n channel_id: undefined, // not needed for comment drafts; see below\n body: 'Hello from the Front Core API quickstart (draft, not sent).',\n mode: 'private', // private comment draft, never emailed to the customer\n }),\n });\n console.log('Created draft comment:', draft.id ?? draft);\n}"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_e490b727cbb04f3d8be1804b",
"tool_kind": "file_edit"
}Recorded tool result
{
"type": "tool_result",
"seq": 37,
"ts": "2026-10-13T20:21:31.522Z",
"turn": 1,
"output": {
"content": [
{
"text": "Successfully replaced 1 block(s) in /sandbox/repo/front-example/example.mjs.",
"type": "text"
}
],
"details": {
"diff": " ...\n 41 for (const c of convos._results ?? []) {\n 42 console.log(`Conversation [${c.status}] ${c.subject ?? '(no subject)'} (${c.id})`);\n 43 }\n 44 \n-45 // Create a draft reply in the first conversation found (safe, non-sending write op)\n+45 // Post an internal comment on the newest conversation (safe: never emailed to customers)\n 46 const first = convos._results?.[0];\n 47 if (first) {\n-48 const inbox = await api(`/conversations/${first.id}/inbox`);\n-49 const draft = await api(`/conversations/${first.id}/drafts`, {\n+48 const teammates = await api('/teammates?limit=1');\n+49 const author = teammates._results?.[0];\n+50 const comment = await api(`/conversations/${first.id}/comments`, {\n 50 method: 'POST',\n 51 body: JSON.stringify({\n-52 channel_id: undefined, // not needed for comment drafts; see below\n-53 body: 'Hello from the Front Core API quickstart (draft, not sent).',\n-54 mode: 'private', // private comment draft, never emailed to the customer\n+53 author_id: author.id,\n+54 body: `Hello from the Front Core API quickstart (posted by ${author.email}).`,\n 55 }),\n 56 });\n-57 console.log('Created draft comment:', draft.id ?? draft);\n+57 console.log('Posted internal comment:', comment.id);\n 58 }",
"patch": "--- /sandbox/repo/front-example/example.mjs\n+++ /sandbox/repo/front-example/example.mjs\n@@ -41,18 +41,18 @@\n for (const c of convos._results ?? []) {\n console.log(`Conversation [${c.status}] ${c.subject ?? '(no subject)'} (${c.id})`);\n }\n \n-// Create a draft reply in the first conversation found (safe, non-sending write op)\n+// Post an internal comment on the newest conversation (safe: never emailed to customers)\n const first = convos._results?.[0];\n if (first) {\n- const inbox = await api(`/conversations/${first.id}/inbox`);\n- const draft = await api(`/conversations/${first.id}/drafts`, {\n+ const teammates = await api('/teammates?limit=1');\n+ const author = teammates._results?.[0];\n+ const comment = await api(`/conversations/${first.id}/comments`, {\n method: 'POST',\n body: JSON.stringify({\n- channel_id: undefined, // not needed for comment drafts; see below\n- body: 'Hello from the Front Core API quickstart (draft, not sent).',\n- mode: 'private', // private comment draft, never emailed to the customer\n+ author_id: author.id,\n+ body: `Hello from the Front Core API quickstart (posted by ${author.email}).`,\n }),\n });\n- console.log('Created draft comment:', draft.id ?? draft);\n+ console.log('Posted internal comment:', comment.id);\n }\n",
"firstChangedLine": 45
}
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_e490b727cbb04f3d8be1804b",
"is_error": false,
"tool_kind": "file_edit"
}cd /sandbox/repo/front-example && node example.mjs; echo "exit=$?"
Set FRONT_API_TOKEN first (Front > Settings > Developers > API Tokens).
Set FRONT_API_TOKEN first (Front > Settings > Developers > API Tokens). exit=1
Recorded tool call
{
"type": "tool_call",
"seq": 39,
"ts": "2026-10-13T20:21:33.818Z",
"name": "bash",
"turn": 1,
"input": {
"command": "cd /sandbox/repo/front-example && node example.mjs; echo \"exit=$?\""
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_a07b90ee58824e2ba6bd6f06",
"tool_kind": "shell"
}Recorded tool result
{
"type": "tool_result",
"seq": 40,
"ts": "2026-10-13T20:21:33.818Z",
"turn": 1,
"output": {
"content": [
{
"text": "Set FRONT_API_TOKEN first (Front > Settings > Developers > API Tokens).\nexit=1\n",
"type": "text"
}
]
},
"run_id": "cmv74jhh5007j0jo5mi3qsaw5",
"tool_id": "call_a07b90ee58824e2ba6bd6f06",
"is_error": false,
"tool_kind": "shell"
}›Thinking…
Done. Now summarize: what I built, pricing, manageability, and the block (no API token in this environment, so I couldn't execute against a real Front instance).
Done — here's the summary.
What Front is and the example I built
Front is a hosted shared-inbox / customer operations platform (front.com). It has a real developer workflow: a REST Core API (api2.frontapp.com), an official JS SDK (npm i frontapp), webhooks, and a Plugin SDK for sidebar apps.
I wrote front-example/ in the repo:
example.mjs— a dependency-free Node script (Node's built-infetch) that: authenticates viaGET /me, lists inboxes and recent conversations, and posts a safe internal comment (never emailed to a customer) on the newest conversation.README.md— how to mint an API token (Settings → Company → Developers → API Tokens) and run it.
Everything targets the hosted API — no local stacks, nothing long-running.
Pricing (verified from front.com/pricing just now)
Per seat/month: Starter $25 annual ($35 monthly), Professional $65 annual ($85 monthly), Enterprise $105 (annual only). There's a 14-day free trial. AI features are add-ons priced per conversation ($0.05–$0.89 depending on autonomy level), and API-throughput increases are a paid add-on ($200 per block). The Core API itself is included in plans, with rate limits varying by tier. Caveat: pricing changes often — double-check the pricing page before committing.
Manageability for me
Easy. It's pure hosted SaaS with a clean REST API, bearer-token auth, pagination, and webhooks — exactly the kind of product I can operate end-to-end (read/write conversations, manage contacts/tags, build plugins) with just a token. Nothing here is a blocker in principle.
Where I got blocked
I don't have a Front account or API token in this environment (no FRONT_API_TOKEN), so the script is written and syntax-verified but I could not execute it against a live Front instance — it exits cleanly asking for the token. If you can provide a token (or a trial account; the 14-day trial is free), I can run it and iterate immediately.
AX Fundamentals
23 checks. Open an area for details.
This check is a quick preview. Test more tasks and models with Gauge Agents.
Test your product with Gauge Agents