Ads-Cockpit API Documentation
Overview
The Ads-Cockpit API provides two authentication methods:
- JWT Authentication - For the web application (user sessions)
- API Key Authentication - For external integrations (MCP, AI agents, scripts)
Base URL: https://app.firemetrix.io/api/v1
For local development: https://app.firemetrix.io/api/v1
Authentication
JWT Authentication
Used by the web application for user sessions.
Authorization: Bearer <jwt_token>
Obtain a token via Google OAuth at POST /auth/google.
API Key Authentication
Used for external integrations. API keys are created in Settings → API Keys.
X-API-Key: acs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Key Format: acs_ + 32 random characters
Available Scopes:
| Scope | Description |
|---|---|
campaigns:read | Query campaign data, search terms, daily metrics |
products:read | Query product data, details, daily metrics, feeds |
accounts:read | Query account data, details, daily metrics, campaigns |
search_terms:read | Account search terms, mining runs/suggestions, negative keywords |
customers:read | Customer profiles and memories |
customers:write | Update customer profiles, create/delete memories |
planning:read | Board, calendar, todos |
planning:write | Move board cards, update card settings, CRUD todos, set assignees |
logs:read | Activity logs (account + team) |
logs:write | Create activity logs (account + team) |
External Query API
Read and write endpoints for external integrations (MCP, AI agents, scripts). Requires API key authentication.
GET/query/campaigns
Query campaigns with performance metrics.
Required Scope: campaigns:read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
account_id | string | - | Filter by account ID |
status | string | - | Filter by status: ENABLED, PAUSED, REMOVED |
channel_type | string | - | Filter by channel: SEARCH, SHOPPING, DISPLAY, PERFORMANCE_MAX |
days | integer | 30 | Performance data for last N days (max: 365) |
min_cost | float | - | Minimum cost in EUR |
max_cost | float | - | Maximum cost in EUR |
min_roas | float | - | Minimum ROAS |
max_roas | float | - | Maximum ROAS |
sort | string | -cost | Sort field: cost, roas, conversions, clicks, impressions, name. Prefix with - for descending |
limit | integer | 100 | Results per page (max: 1000) |
offset | integer | 0 | Pagination offset |
Example Request:
curl -H "X-API-Key: acs_xxx" \
"https://app.firemetrix.io/api/v1/query/campaigns?status=ENABLED&days=30&sort=-roas&limit=10"
Example Response:
{
"data": [
{
"id": "17539449348",
"accountId": "7664254989",
"accountName": "Example Account",
"name": "Campaign Name",
"status": "ENABLED",
"channelType": "PERFORMANCE_MAX",
"metrics": {
"periodDays": 30,
"cost": 1234.56,
"impressions": 50000,
"clicks": 2500,
"conversions": 125,
"conversionValue": 8750.00,
"roas": 7.08,
"ctr": 0.05,
"cpc": 0.49
}
}
],
"meta": {
"total": 207,
"limit": 10,
"offset": 0
}
}
GET/query/products
Query products with performance and price data.
Required Scope: products:read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
account_id | string | - | Filter by account ID |
days | integer | 30 | Performance data for last N days (max: 365) |
min_roas | float | - | Minimum ROAS |
max_roas | float | - | Maximum ROAS |
price_vs_benchmark | string | - | Price comparison: above, below, equal |
min_price_diff_percent | float | - | Minimum price difference % vs benchmark |
availability | string | - | Filter: in_stock, out_of_stock |
brand | string | - | Filter by brand name |
has_impressions | boolean | - | Only products with impressions (true) |
sort | string | -cost | Sort field: cost, roas, price_diff, price |
limit | integer | 100 | Results per page (max: 1000) |
offset | integer | 0 | Pagination offset |
Example Request:
curl -H "X-API-Key: acs_xxx" \
"https://app.firemetrix.io/api/v1/query/products?price_vs_benchmark=above&max_roas=2&limit=5"
Example Response:
{
"data": [
{
"offerId": "SKU123",
"title": "Product Name",
"brand": "Brand X",
"price": 49.99,
"benchmarkPrice": 39.99,
"priceDiffPercent": 25.0,
"availability": "in_stock",
"metrics": {
"periodDays": 30,
"impressions": 1200,
"clicks": 45,
"cost": 22.50,
"conversionValue": 149.97,
"roas": 6.66
}
}
],
"meta": {
"total": 156,
"limit": 5,
"offset": 0
}
}
GET/query/accounts
Query accounts with aggregated performance metrics.
Required Scope: accounts:read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
mcc_id | string | - | Filter sub-accounts by MCC account ID |
search | string | - | Search accounts by name (case-insensitive, partial match) |
days | integer | 30 | Performance data for last N days (max: 365) |
min_roas | float | - | Minimum ROAS |
sort | string | -cost | Sort field: cost, roas, conversions, name |
limit | integer | 100 | Results per page (max: 1000) |
offset | integer | 0 | Pagination offset |
Example Requests:
# All accounts sorted by ROAS
curl -H "X-API-Key: acs_xxx" \
"https://app.firemetrix.io/api/v1/query/accounts?days=30&sort=-roas"
# Sub-accounts of a specific MCC
curl -H "X-API-Key: acs_xxx" \
"https://app.firemetrix.io/api/v1/query/accounts?mcc_id=8427925949"
# Search by name
curl -H "X-API-Key: acs_xxx" \
"https://app.firemetrix.io/api/v1/query/accounts?search=bodenverkauf"
Example Response:
{
"data": [
{
"id": "7664254989",
"name": "Example Account",
"currency": "EUR",
"status": "active",
"isMcc": false,
"metrics": {
"periodDays": 30,
"cost": 24804.95,
"impressions": 2776311,
"clicks": 46702,
"conversions": 1278.17,
"conversionValue": 151336.90,
"roas": 6.10
}
}
],
"meta": {
"total": 66,
"limit": 100,
"offset": 0
}
}
GET/query/team/members
List all team members with their IDs, roles, and contact info. Useful for getting user UUIDs needed for todo assignments and log attribution.
Required Scope: accounts:read
Example Request:
curl -H "X-API-Key: acs_xxx" \
"https://app.firemetrix.io/api/v1/query/team/members"
Example Response:
{
"data": [
{
"id": "c78b0c33-1234-5678-abcd-ef1234567890",
"email": "user@example.com",
"name": "Max Mustermann",
"avatarUrl": "https://lh3.googleusercontent.com/...",
"role": "owner",
"joinedAt": "2025-12-01T10:00:00Z"
}
],
"count": 1
}
GET/query/accounts/{accountID}
Get account details with metadata.
Required Scope: accounts:read
Example Request:
curl -H "X-API-Key: acs_xxx" \
"https://app.firemetrix.io/api/v1/query/accounts/7664254989"
GET/query/accounts/{accountID}/metrics/daily
Get daily aggregated metrics for an account.
Required Scope: accounts:read
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date | string | Yes | Start date (YYYY-MM-DD) |
end_date | string | Yes | End date (YYYY-MM-DD) |
GET/query/accounts/{accountID}/campaigns
List campaigns for an account. Optionally include metrics summary.
Required Scope: accounts:read
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date | string | No | Start date for metrics summary |
end_date | string | No | End date for metrics summary |
GET/query/campaigns/{campaignID}/search-terms
Get search term insights for a campaign.
Required Scope: campaigns:read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
days | integer | 30 | Analysis period (max: 90) |
GET/query/campaigns/{campaignID}/metrics/daily
Get daily metrics for a campaign.
Required Scope: campaigns:read
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
start_date | string | No | Start date (YYYY-MM-DD) |
end_date | string | No | End date (YYYY-MM-DD) |
days | integer | 30 | Fallback if dates not provided (max: 365) |
GET/query/products/{offerID}
Get product details.
Required Scope: products:read
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | string | Yes | The Google Ads account ID |
GET/query/products/{offerID}/metrics/daily
Get daily metrics for a product.
Required Scope: products:read
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
account_id | string | Yes | The Google Ads account ID |
start_date | string | Yes | Start date (YYYY-MM-DD) |
end_date | string | Yes | End date (YYYY-MM-DD) |
GET/query/accounts/{accountID}/feeds
List product feeds for an account.
Required Scope: products:read
GET/query/accounts/{accountID}/search-terms
Get aggregated search terms for an account.
Required Scope: search_terms:read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
days | integer | 30 | Analysis period (max: 365) |
GET/query/accounts/{accountID}/mining/runs
List keyword mining runs for an account.
Required Scope: search_terms:read
GET/query/accounts/{accountID}/mining/runs/{runID}
Get a specific mining run with category breakdown.
Required Scope: search_terms:read
GET/query/accounts/{accountID}/mining/runs/{runID}/suggestions
Get suggestions for a specific mining run.
Required Scope: search_terms:read
GET/query/accounts/{accountID}/mining/suggestions/pending
Get all pending (unreviewed) suggestions for an account.
Required Scope: search_terms:read
GET/query/accounts/{accountID}/negative-keywords
List negative keyword lists for an account.
Required Scope: search_terms:read
GET/query/accounts/{accountID}/negative-keywords/{listID}
Get a specific negative keyword list with all keywords.
Required Scope: search_terms:read
GET/query/accounts/{accountID}/customer-profile
Get customer profile for an account.
Required Scope: customers:read
GET/query/accounts/{accountID}/memories
Get customer memories for an account.
Required Scope: customers:read
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
category | string | No | Filter by category: allgemein, kundengespraeche, sonstige |
GET/query/planning/board
Get the planning board with all cards.
Required Scope: planning:read
GET/query/planning/status-config
Get board status configuration (labels and colors).
Required Scope: planning:read
GET/query/planning/calendar
Get calendar events in a date range.
Required Scope: planning:read
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
start | string | Yes | Start date (YYYY-MM-DD) |
end | string | Yes | End date (YYYY-MM-DD) |
GET/query/accounts/{accountID}/todos
List todos for an account.
Required Scope: planning:read
Response: Array of PlanningTodoWithAssignee objects:
[
{
"id": "uuid",
"accountId": "7664254989",
"title": "Budget-Optimierung durchführen",
"description": "ROAS-Ziele überprüfen und Budgets anpassen",
"dueDate": "2026-02-20",
"assignedTo": "uuid",
"isCompleted": false,
"assigneeName": "Max Müller",
"assigneeAvatarUrl": "https://..."
}
]
GET/query/accounts/{accountID}/logs
Get activity logs for an account.
Required Scope: logs:read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 0 | Results per page |
offset | integer | 0 | Pagination offset |
log_type | string | - | Filter: manual, ai_insight, google_ads, system, user_action, sync |
GET/query/logs
Get all activity logs for the team.
Required Scope: logs:read
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 0 | Results per page |
offset | integer | 0 | Pagination offset |
log_type | string | - | Filter by log type |
External Write API
Write endpoints for external integrations. Requires API key with the corresponding write scope.
PUT/query/accounts/{accountID}/customer-profile
Update customer profile for an account (partial update — all fields optional).
Required Scope: customers:write
Request Body:
{
"customerType": "E-Commerce",
"servicesProducts": "Bio-Lebensmittel Online-Shop",
"industry": "Lebensmittel",
"websiteStrengths": ["Gute Produktbilder", "Schneller Versand"],
"websiteWeaknesses": ["Keine Bewertungen"]
}
Response: Updated CustomerProfile object.
POST/query/accounts/{accountID}/memories
Create a new customer memory entry.
Required Scope: customers:write
Request Body:
{
"category": "kundengespraeche",
"content": "Kunde möchte Budget auf 5000€/Monat erhöhen",
"entryDate": "2026-02-14T10:00:00Z",
"userId": "uuid"
}
category:allgemein,kundengespraeche, orsonstigeentryDate: Optional, defaults to nowuserId: Optional, for tracking who created the entry
Response: Created CustomerMemory object (201).
DELETE/query/accounts/{accountID}/memories/{memoryID}
Delete a customer memory entry.
Required Scope: customers:write
Response: {"status": "ok"}
POST/query/accounts/{accountID}/logs
Create an activity log entry for an account.
Required Scope: logs:write
Request Body:
{
"logType": "ai_insight",
"message": "ROAS um 15% gestiegen nach Budget-Anpassung",
"metadata": {"roas_before": 3.2, "roas_after": 3.7},
"userId": "uuid",
"eventDate": "2026-01-30"
}
logType:manual,ai_insight,google_ads,system,user_action,sync,errormetadata: Optional JSON objectuserId: OptionaleventDate: Optional date (YYYY-MM-DD) when the event occurred. Used for chart positioning instead ofcreatedAt.
Response: Created ActivityLog object (201).
POST/query/logs
Create a team-level activity log entry (not tied to a specific account).
Required Scope: logs:write
Request Body:
{
"logType": "system",
"message": "Automatische Budget-Analyse abgeschlossen",
"accountId": "system"
}
accountId: Optional, defaults to"system"
Response: Created ActivityLog object (201).
PUT/query/planning/board/{accountID}/move
Move a board card to a new status and position.
Required Scope: planning:write
Request Body:
{
"status": "zu_bearbeiten",
"position": 0,
"userId": "uuid"
}
status:onboarding,setup,wartend,zu_bearbeiten,rueckfragenposition: 0-based position within the status columnuserId: Optional, for tracking who moved the card
Response: {"status": "ok"}
PUT/query/planning/board/{accountID}/settings
Update card settings (cycle duration, due date).
Required Scope: planning:write
Request Body:
{
"cycleDurationDays": 14,
"dueDate": "2026-03-01",
"clearDueDate": false
}
Response: {"status": "ok"}
POST/query/planning/todos
Create a new planning todo.
Required Scope: planning:write
Request Body:
{
"accountId": "7664254989",
"title": "Budget-Optimierung durchführen",
"description": "ROAS-Ziele überprüfen und Budgets anpassen",
"dueDate": "2026-02-20",
"assignedTo": "uuid",
"userId": "uuid"
}
accountIdandtitleare requireddescription: Optional text descriptiondueDate: Optional due date (YYYY-MM-DD)assignedTo: Optional user UUID for assignmentuserId: Optional user UUID for tracking who created the todo (if omitted,createdBywill be null)
Response: Created PlanningTodoWithAssignee object (201).
PATCH/query/planning/todos/{todoID}
Update a planning todo (partial update).
Required Scope: planning:write
Request Body:
{
"title": "Updated title",
"description": "Detailed description of the task",
"dueDate": "2026-02-20",
"assignedTo": "uuid",
"isCompleted": true,
"userId": "uuid"
}
- All fields optional
description: Text description (set tonullto clear)assignedTo: User UUID (set tonullto unassign)userId: Optional, for tracking who completed/updated the todo
Response: Updated PlanningTodoWithAssignee object.
DELETE/query/planning/todos/{todoID}
Delete a planning todo.
Required Scope: planning:write
Response: {"status": "ok"}
PUT/query/accounts/{accountID}/assignees
Set the user assignments for an account (replaces all existing assignments).
Required Scope: planning:write
Request Body:
{
"userIds": ["uuid-1", "uuid-2"]
}
- Pass empty array to remove all assignments
Response: {"status": "ok"}
API Key Management
API keys are managed via JWT-authenticated endpoints.
GET/teams/{teamId}/api-keys
List all API keys for a team.
Required Role: Any team member
Response:
[
{
"id": "uuid",
"teamId": "uuid",
"name": "MCP Integration",
"keyPrefix": "acs_LCLf",
"scopes": ["campaigns:read", "products:read", "accounts:read"],
"lastUsedAt": "2026-01-30T18:00:00Z",
"expiresAt": null,
"createdAt": "2026-01-30T17:00:00Z"
}
]
POST/teams/{teamId}/api-keys
Create a new API key.
Required Role: Admin or Owner
Request Body:
{
"name": "MCP Integration",
"scopes": ["campaigns:read", "products:read", "accounts:read"],
"expiresAt": "2027-01-30T00:00:00Z" // optional
}
Response:
{
"id": "uuid",
"teamId": "uuid",
"name": "MCP Integration",
"keyPrefix": "acs_LCLf",
"scopes": ["campaigns:read", "products:read", "accounts:read"],
"key": "acs_LCLfhM4D2EMMTN3yPIMrePHYV4aUPMwA", // Only returned once!
"createdAt": "2026-01-30T17:00:00Z"
}
⚠️ Important: The full API key is only returned once upon creation. Store it securely.
DELETE/teams/{teamId}/api-keys/{keyId}
Delete an API key.
Required Role: Admin or Owner
Response:
{
"message": "API key deleted"
}
Error Responses
All endpoints return errors in this format:
{
"code": "error_code",
"message": "Human-readable error message"
}
Common Error Codes:
| HTTP Status | Code | Description |
|---|---|---|
| 400 | bad_request | Invalid request parameters |
| 401 | api_key_required | Missing X-API-Key header |
| 401 | invalid_api_key | API key not found or invalid |
| 401 | expired_api_key | API key has expired |
| 403 | insufficient_scope | API key lacks required scope |
| 403 | forbidden | User lacks permission |
| 404 | not_found | Resource not found |
| 500 | internal | Internal server error |
MCP Integration Example
To use this API with Claude's Model Context Protocol (MCP):
- Create an API key in Settings → API Keys with required scopes
- Configure your MCP server to use the query endpoints
- The API returns structured JSON that can be directly consumed by AI agents
Example MCP Tool Definition:
{
"name": "query_campaigns",
"description": "Query Google Ads campaigns with performance metrics",
"parameters": {
"days": { "type": "integer", "default": 30 },
"status": { "type": "string", "enum": ["ENABLED", "PAUSED"] },
"min_roas": { "type": "number" },
"limit": { "type": "integer", "default": 10 }
}
}
Rate Limits
Currently no rate limits are enforced. This may change in future versions.
Campaign Details API (JWT)
Endpoints for fetching detailed campaign structure data. Requires JWT authentication.
GET/campaigns/{campaignId}/details
Fetch full campaign details including PMax asset groups, listing groups, and settings.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | The Google Ads account ID |
Example Request:
curl -H "Authorization: Bearer <jwt_token>" \
"https://app.firemetrix.io/api/v1/campaigns/17539449348/details?accountId=7664254989"
Example Response (PMax Campaign):
{
"settings": {
"id": "17539449348",
"name": "PMax Campaign",
"status": "ENABLED",
"channelType": "PERFORMANCE_MAX",
"biddingStrategy": "MAXIMIZE_CONVERSION_VALUE",
"targetRoas": 4.0,
"dailyBudget": 100.0,
"startDate": "2025-01-01",
"endDate": null
},
"campaignType": "PERFORMANCE_MAX",
"pmax": {
"assetGroups": [
{
"id": "123456",
"name": "Asset Group 1",
"status": "ENABLED",
"adStrength": "GOOD",
"finalUrls": ["https://example.com"],
"assets": [
{
"id": "789",
"type": "TEXT",
"fieldType": "HEADLINE",
"performanceLabel": "BEST",
"text": "Great Product"
}
]
}
],
"listingGroups": [
{
"id": "456",
"assetGroupId": "123456",
"type": "UNIT_INCLUDED",
"caseValue": { "dimension": "BRAND", "value": "MyBrand" }
}
],
"lowPerformanceAssets": []
},
"geoTargets": [
{ "id": "2276", "name": "Germany", "countryCode": "DE", "targetType": "LOCATION" }
]
}
GET/campaigns/{campaignId}/settings
Fetch campaign settings only (lightweight endpoint).
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | The Google Ads account ID |
Example Response:
{
"id": "17539449348",
"name": "PMax Campaign",
"status": "ENABLED",
"channelType": "PERFORMANCE_MAX",
"biddingStrategy": "MAXIMIZE_CONVERSION_VALUE",
"targetRoas": 4.0,
"dailyBudget": 100.0
}
GET/campaigns/{campaignId}/ai-context
Fetch enriched campaign data optimized for AI analysis.
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
accountId | string | Yes | The Google Ads account ID |
Example Response:
{
"campaignType": "PERFORMANCE_MAX",
"settings": { ... },
"performance": {
"cost": 1234.56,
"conversions": 45.5,
"conversionValue": 5500.00,
"roas": 4.45
},
"typeSpecific": {
"assetGroupCount": 3,
"lowPerformanceAssetCount": 2,
"listingGroupCount": 15
},
"issues": [
{
"severity": "warning",
"message": "2 assets with LOW performance rating"
}
]
}
Keyword Mining API (JWT)
AI-powered negative keyword mining with approval workflow.
All endpoints require JWT authentication and are under /api/v1/accounts/{accountID}/mining.
| Method | Path | Description |
|---|---|---|
| POST | /start | Start mining run (calls Gemini, uses 1 credit) |
| GET | /runs | List mining run history |
| GET | /runs/{runID} | Get run with category breakdown |
| GET | /runs/{runID}/suggestions | Get suggestions for a run |
| GET | /suggestions/pending | Get all pending suggestions |
| PUT | /suggestions/{suggestionID} | Approve/reject single suggestion |
| POST | /suggestions/bulk-review | Bulk approve/reject |
| POST | /suggestions/apply | Apply approved suggestions to negative keyword lists (one per category) |
| GET | /search-terms | Account-wide aggregated search terms |
POST/accounts/{accountID}/mining/start
Starts an AI mining run analyzing search terms to suggest negative keywords grouped by category.
Request Body (optional):
{
"dateRangeStart": "2026-01-01",
"dateRangeEnd": "2026-01-31"
}
Response: MiningRunWithCategories — run metadata + categories with suggestions.
POST/accounts/{accountID}/mining/suggestions/bulk-review
Request Body:
{
"suggestionIds": ["uuid1", "uuid2"],
"status": "approved"
}
POST/accounts/{accountID}/mining/suggestions/apply
Applies all approved suggestions. Creates one negative keyword list per category.
Response: Array of created NegativeKeywordList objects.
Public Endpoints
GET/auth/maintenance-status
Check if the system is in maintenance mode. This endpoint is always accessible, even during maintenance.
Example Request:
curl "https://app.firemetrix.io/api/v1/auth/maintenance-status"
Example Response (Maintenance Active):
{
"maintenance": true,
"message": "System-Update läuft. Bitte warten...",
"estimatedEndTime": "2026-02-05T15:30:00Z"
}
Example Response (System Online):
{
"maintenance": false,
"message": "",
"estimatedEndTime": null
}
During maintenance mode, all other API endpoints return HTTP 503:
{
"error": "maintenance",
"message": "System-Update läuft. Bitte warten...",
"maintenance": true,
"estimatedEndTime": "2026-02-05T15:30:00Z"
}
Favorites API (JWT)
Manage per-user account favorites. Requires JWT authentication.
GET/favorites
List all favorite accounts for the current user.
Example Request:
curl -H "Authorization: Bearer <jwt_token>" \
"https://app.firemetrix.io/api/v1/favorites"
Example Response:
[
{
"accountId": "7664254989",
"name": "bodenverkauf"
}
]
POST/favorites/{accountID}
Toggle favorite status for an account. Adds if not favorited, removes if already favorited.
Example Request:
curl -X POST -H "Authorization: Bearer <jwt_token>" \
"https://app.firemetrix.io/api/v1/favorites/7664254989"
Example Response:
{
"isFavorited": true
}
Team Settings API (JWT)
Manage team-level settings for kunde role permissions. Requires JWT authentication with admin or owner role.
GET/teams/{teamId}/settings
Get team settings.
Example Response:
{
"teamId": "uuid",
"kundeCanViewSearchTerms": false,
"kundeCanViewNegativeLists": false,
"kundeCanCreateFeeds": false
}
PUT/teams/{teamId}/settings
Update team settings.
Required Role: Admin or Owner
Request Body:
{
"kundeCanViewSearchTerms": true,
"kundeCanViewNegativeLists": true,
"kundeCanCreateFeeds": false
}
Response: Updated team settings object.
Account Assignments API (JWT)
Manage account assignments for team members. Allows admins to restrict member access to specific accounts. Requires JWT authentication with admin or owner role.
GET/teams/{teamID}/members/{memberID}/assignments
Get the list of accounts assigned to a specific team member.
Required Role: Admin or Owner
Example Request:
curl -H "Authorization: Bearer <jwt_token>" \
"https://app.firemetrix.io/api/v1/teams/{teamID}/members/{memberID}/assignments"
Example Response:
{
"accountIds": ["7664254989", "8427925949"]
}
Notes:
- Returns empty array if member has no assignments (meaning they have access to all accounts)
- Only applies to members with role
memberorkunde - Admins and owners always have access to all accounts regardless of assignments
PUT/teams/{teamID}/members/{memberID}/assignments
Update the account assignments for a team member. Replaces all existing assignments.
Required Role: Admin or Owner
Request Body:
{
"accountIds": ["7664254989", "8427925949"]
}
Response:
{
"message": "Account assignments updated"
}
Notes:
- Pass an empty array
[]to remove all assignments (grants access to all accounts) - Only valid for members with role
memberorkunde - Returns error if trying to assign accounts to admin or owner roles
- Validates that all account IDs exist and belong to the team
Planning API (JWT)
Board, Calendar, and Todo management for account planning. Requires JWT authentication.
GET/planning/status-config
Returns the 5 board status configurations (label and color per status).
Response: BoardStatusConfig[]
[
{ "status": "onboarding", "label": "Onboarding", "color": "blue", "updatedAt": "..." },
{ "status": "setup", "label": "Setup", "color": "purple", "updatedAt": "..." },
...
]
PUT/planning/status-config/{status}
Update label and color for a board status.
Body: { "label": "Neukunden", "color": "green" }
Valid status keys: onboarding, setup, wartend, zu_bearbeiten, rueckfragen
Valid colors: blue, purple, amber, red, orange, green, emerald, teal, cyan, indigo, pink, rose, sky, lime, yellow, slate
GET/planning/board
Returns all board cards with account names. Automatically creates cards for new accounts and moves overdue "wartend" cards to "zu_bearbeiten".
Response: BoardCardWithAccount[]
PUT/planning/board/{accountID}/move
Move a card to a new status column.
Body: { "status": "wartend", "position": 0 }
Status values: onboarding, setup, wartend, zu_bearbeiten, rueckfragen
When moving to "wartend" with cycleDurationDays set, dueDate is auto-calculated.
PUT/planning/board/{accountID}/settings
Update card settings (cycle duration).
Body: { "cycleDurationDays": 14 }
GET/planning/calendar?start=2026-02-01&end=2026-02-28
Returns merged calendar events: manual entries + automatic due dates.
Response: CalendarEvent[] with source: "manual" | "due_date" | "todo", isEcommerce, logoUrl
POST/planning/calendar
Create a manual calendar entry.
Body: { "accountId": "1234567890", "scheduledDate": "2026-02-15", "note": "Kundengespräch" }
PATCH/planning/calendar/{entryID}
Update the scheduled date of a manual calendar entry (used by drag & drop).
Body: { "scheduledDate": "2026-02-20" }
DELETE/planning/calendar/{entryID}
Delete a manual calendar entry.
GET/planning/accounts/{accountID}/todos
List all todos for an account with assignee names.
POST/planning/todos
Create a new todo.
Body: { "accountId": "1234567890", "title": "Budget prüfen", "dueDate": "2026-02-20", "assignedTo": "uuid" }
PUT/planning/todos/{todoID}
Update a todo (title, description, dueDate, assignedTo, isCompleted).
DELETE/planning/todos/{todoID}
Delete a todo.
Promotions API (JWT)
Merchant Center promotions management. Requires JWT authentication.
GET/accounts/{accountID}/promotions
List promotions for an account. By default returns upcoming/active promotions.
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
upcoming | string | "true" | Return upcoming/active promotions (default behavior) |
past | string | - | Set to "true" to return expired/past promotions with pagination |
page | integer | 1 | Page number (only with past=true) |
pageSize | integer | 10 | Results per page, max 100 (only with past=true) |
startDate | string | - | Filter by date range start (YYYY-MM-DD) |
endDate | string | - | Filter by date range end (YYYY-MM-DD) |
Response (default / upcoming): Plain array of MerchantPromotion objects.
Response (past=true): Paginated response:
{
"data": [
{
"id": "uuid",
"accountId": "7664254989",
"promotionId": "PROMO_123",
"title": "Summer Sale",
"couponValueType": "PERCENT_OFF",
"percentOff": 20,
"effectiveStart": "2026-06-01T00:00:00Z",
"effectiveEnd": "2026-06-30T23:59:59Z",
"overallStatus": "EXPIRED",
"customTitle": null,
"customNotes": null
}
],
"total": 42,
"page": 1,
"pageSize": 10
}
PATCH/accounts/{accountID}/promotions/{promotionID}
Update custom fields for a promotion. All fields are optional. Send empty string "" to clear a field.
Request Body:
{
"customTitle": "My Custom Title",
"customEffectiveStart": "2026-03-01T00:00:00Z",
"customEffectiveEnd": "2026-03-31T23:59:59Z",
"customNotes": "Internal note about this promotion"
}
customTitle: Override the synced title (send""to clear)customEffectiveStart: Override the effective start date (RFC 3339 format, send""to clear)customEffectiveEnd: Override the effective end date (RFC 3339 format, send""to clear)customNotes: Free-text notes (send""to clear)
Response: Updated MerchantPromotion object.
Billing API (JWT)
AI Chat
Streaming AI chat with account context. Requires JWT authentication.
| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /chat/stream | JWT | Stream AI chat response via SSE |
POST/chat/stream
Streams a Gemini-powered chat response as Server-Sent Events. Deducts 1 AI credit per message.
Request Body:
{
"message": "Wie performen meine Kampagnen?",
"history": [
{ "role": "user", "content": "Hallo" },
{ "role": "model", "content": "Hallo! Wie kann ich helfen?" }
],
"accountId": "8427925949"
}
Response: SSE stream with data: {"text":"..."} chunks, terminated by data: [DONE].
Errors: 402 (credits exhausted), 503 (Gemini not configured).
Stripe billing management. Requires JWT authentication.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /billing/status | JWT | Get billing status (plan, subscription, credits) |
| GET | /billing/invoices | JWT | List paid invoices with PDF download links |
| POST | /billing/checkout | JWT (Owner) | Create Stripe Checkout session |
| POST | /billing/portal | JWT (Owner) | Create Stripe Customer Portal session |
| PUT | /billing/addon | JWT (Owner) | Add/change E-Commerce addon tier |
| DELETE | /billing/addon | JWT (Owner) | Remove E-Commerce addon |
| POST | /billing/webhook | None | Stripe webhook endpoint |
GET/billing/invoices
List all paid Stripe invoices for the tenant. Any team member can access this endpoint.
Example Response:
[
{
"id": "in_1234567890",
"number": "INV-0001",
"date": 1707350400,
"amountPaid": 4900,
"currency": "eur",
"status": "paid",
"pdfUrl": "https://pay.stripe.com/invoice/...",
"hostedUrl": "https://invoice.stripe.com/i/..."
}
]
Notes:
dateis a Unix timestampamountPaidis in the smallest currency unit (cents)pdfUrllinks to the Stripe-generated PDF invoice- Returns empty array if tenant has no Stripe customer
Changelog
v1.11.0 (2026-02-16)
- Added custom fields to
merchant_promotions:custom_title,custom_effective_start,custom_effective_end,custom_notes GET /accounts/{accountID}/promotionsnow supports?past=true&page=1&pageSize=10for paginated past promotions- New endpoint:
PATCH /accounts/{accountID}/promotions/{promotionID}for updating custom fields
v1.10.0 (2026-02-14)
- Added
mcc_idfilter toGET /query/accounts— filter sub-accounts by MCC - Added
searchfilter toGET /query/accounts— search accounts by name (case-insensitive) - New endpoint:
GET /query/team/members— list team members with UUIDs (scope:accounts:read)
v1.9.0 (2026-02-14)
- Added write scopes to External API:
customers:write,planning:write,logs:write - 11 new write endpoints for customer profiles, memories, activity logs, board cards, todos, and account assignees
- Optional
userIdfield in write requests for attribution tracking (defaults to "via API-Key") - New repo method
SetAccountAssigneesfor account-centric assignment management
v1.8.0 (2026-02-14)
- Extended External Query API to full read access (~25 new endpoints)
- New scopes:
search_terms:read,customers:read,planning:read,logs:read - Added search_path middleware for API key routes (proper tenant isolation)
- New endpoints: account details/daily metrics/campaigns, campaign search terms/daily metrics, product details/daily metrics/feeds, search terms/mining/negative keywords, customer profiles/memories, planning board/calendar/todos, activity logs
v1.7.0 (2026-02-13)
- Added Planning feature API: Board, Calendar, Todos
- New endpoints under
/planning/*
v1.6.0 (2026-02-08)
- Added Stripe Billing API with checkout, portal, addons, and invoices
- New endpoints:
/billing/status,/billing/invoices,/billing/checkout,/billing/portal,/billing/addon,/billing/webhook - New tables:
public.stripe_webhook_events,public.subscription_addons - Extended
public.tenantswith subscription fields
v1.5.0 (2026-02-07)
- Added per-team MCC visibility: each team can independently control which MCCs are visible and synced
- New endpoint:
GET /teams/{teamID}/mcc-visibility— returns visibility map for a team PUT /teams/{teamID}/mcc-sync-enablednow writes toteam_mcc_visibilityjunction table and recomputesaccounts.sync_enabled- Sync service now respects
sync_enabledwhen fetching MCCs from Google Ads API - New table:
team_mcc_visibility
v1.4.0 (2026-02-07)
- Added Account Assignments API for restricting member access to specific accounts
- New endpoints:
GET /teams/{teamID}/members/{memberID}/assignments,PUT /teams/{teamID}/members/{memberID}/assignments - New table:
user_account_assignments
v1.3.0 (2026-02-07)
- Added Favorites API for per-user account favorites
- Added Team Settings API for kunde role opt-in permissions
- RBAC: Renamed
viewerrole tokundewith configurable permissions - New tables:
user_account_favorites,team_settings
v1.2.0 (2026-02-05)
- Added maintenance mode with user notification
- New endpoint:
/auth/maintenance-status - All endpoints return 503 during maintenance (except health and maintenance-status)
v1.1.0 (2026-02-04)
- Added Campaign Details API endpoints for PMax deep-dive
- New endpoints:
/campaigns/{id}/details,/campaigns/{id}/settings,/campaigns/{id}/ai-context - PMax support: asset groups, assets with performance labels, listing groups
v1.0.0 (2026-01-30)
- Initial release of External Query API
- API key authentication with scopes
- Query endpoints for campaigns, products, accounts