Zurück zur Startseite

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:

ScopeDescription
campaigns:readQuery campaign data, search terms, daily metrics
products:readQuery product data, details, daily metrics, feeds
accounts:readQuery account data, details, daily metrics, campaigns
search_terms:readAccount search terms, mining runs/suggestions, negative keywords
customers:readCustomer profiles and memories
customers:writeUpdate customer profiles, create/delete memories
planning:readBoard, calendar, todos
planning:writeMove board cards, update card settings, CRUD todos, set assignees
logs:readActivity logs (account + team)
logs:writeCreate 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:

ParameterTypeDefaultDescription
account_idstring-Filter by account ID
statusstring-Filter by status: ENABLED, PAUSED, REMOVED
channel_typestring-Filter by channel: SEARCH, SHOPPING, DISPLAY, PERFORMANCE_MAX
daysinteger30Performance data for last N days (max: 365)
min_costfloat-Minimum cost in EUR
max_costfloat-Maximum cost in EUR
min_roasfloat-Minimum ROAS
max_roasfloat-Maximum ROAS
sortstring-costSort field: cost, roas, conversions, clicks, impressions, name. Prefix with - for descending
limitinteger100Results per page (max: 1000)
offsetinteger0Pagination 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:

ParameterTypeDefaultDescription
account_idstring-Filter by account ID
daysinteger30Performance data for last N days (max: 365)
min_roasfloat-Minimum ROAS
max_roasfloat-Maximum ROAS
price_vs_benchmarkstring-Price comparison: above, below, equal
min_price_diff_percentfloat-Minimum price difference % vs benchmark
availabilitystring-Filter: in_stock, out_of_stock
brandstring-Filter by brand name
has_impressionsboolean-Only products with impressions (true)
sortstring-costSort field: cost, roas, price_diff, price
limitinteger100Results per page (max: 1000)
offsetinteger0Pagination 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:

ParameterTypeDefaultDescription
mcc_idstring-Filter sub-accounts by MCC account ID
searchstring-Search accounts by name (case-insensitive, partial match)
daysinteger30Performance data for last N days (max: 365)
min_roasfloat-Minimum ROAS
sortstring-costSort field: cost, roas, conversions, name
limitinteger100Results per page (max: 1000)
offsetinteger0Pagination 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:

ParameterTypeRequiredDescription
start_datestringYesStart date (YYYY-MM-DD)
end_datestringYesEnd date (YYYY-MM-DD)

GET/query/accounts/{accountID}/campaigns

List campaigns for an account. Optionally include metrics summary.

Required Scope: accounts:read

Query Parameters:

ParameterTypeRequiredDescription
start_datestringNoStart date for metrics summary
end_datestringNoEnd date for metrics summary

GET/query/campaigns/{campaignID}/search-terms

Get search term insights for a campaign.

Required Scope: campaigns:read

Query Parameters:

ParameterTypeDefaultDescription
daysinteger30Analysis period (max: 90)

GET/query/campaigns/{campaignID}/metrics/daily

Get daily metrics for a campaign.

Required Scope: campaigns:read

Query Parameters:

ParameterTypeRequiredDescription
start_datestringNoStart date (YYYY-MM-DD)
end_datestringNoEnd date (YYYY-MM-DD)
daysinteger30Fallback if dates not provided (max: 365)

GET/query/products/{offerID}

Get product details.

Required Scope: products:read

Query Parameters:

ParameterTypeRequiredDescription
account_idstringYesThe Google Ads account ID

GET/query/products/{offerID}/metrics/daily

Get daily metrics for a product.

Required Scope: products:read

Query Parameters:

ParameterTypeRequiredDescription
account_idstringYesThe Google Ads account ID
start_datestringYesStart date (YYYY-MM-DD)
end_datestringYesEnd 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:

ParameterTypeDefaultDescription
daysinteger30Analysis 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:

ParameterTypeRequiredDescription
categorystringNoFilter 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:

ParameterTypeRequiredDescription
startstringYesStart date (YYYY-MM-DD)
endstringYesEnd 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:

ParameterTypeDefaultDescription
limitinteger0Results per page
offsetinteger0Pagination offset
log_typestring-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:

ParameterTypeDefaultDescription
limitinteger0Results per page
offsetinteger0Pagination offset
log_typestring-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, or sonstige
  • entryDate: Optional, defaults to now
  • userId: 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, error
  • metadata: Optional JSON object
  • userId: Optional
  • eventDate: Optional date (YYYY-MM-DD) when the event occurred. Used for chart positioning instead of createdAt.

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, rueckfragen
  • position: 0-based position within the status column
  • userId: 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"
}
  • accountId and title are required
  • description: Optional text description
  • dueDate: Optional due date (YYYY-MM-DD)
  • assignedTo: Optional user UUID for assignment
  • userId: Optional user UUID for tracking who created the todo (if omitted, createdBy will 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 to null to clear)
  • assignedTo: User UUID (set to null to 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 StatusCodeDescription
400bad_requestInvalid request parameters
401api_key_requiredMissing X-API-Key header
401invalid_api_keyAPI key not found or invalid
401expired_api_keyAPI key has expired
403insufficient_scopeAPI key lacks required scope
403forbiddenUser lacks permission
404not_foundResource not found
500internalInternal server error

MCP Integration Example

To use this API with Claude's Model Context Protocol (MCP):

  1. Create an API key in Settings → API Keys with required scopes
  2. Configure your MCP server to use the query endpoints
  3. 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:

ParameterTypeRequiredDescription
accountIdstringYesThe 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:

ParameterTypeRequiredDescription
accountIdstringYesThe 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:

ParameterTypeRequiredDescription
accountIdstringYesThe 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.

MethodPathDescription
POST/startStart mining run (calls Gemini, uses 1 credit)
GET/runsList mining run history
GET/runs/{runID}Get run with category breakdown
GET/runs/{runID}/suggestionsGet suggestions for a run
GET/suggestions/pendingGet all pending suggestions
PUT/suggestions/{suggestionID}Approve/reject single suggestion
POST/suggestions/bulk-reviewBulk approve/reject
POST/suggestions/applyApply approved suggestions to negative keyword lists (one per category)
GET/search-termsAccount-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 member or kunde
  • 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 member or kunde
  • 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:

ParameterTypeDefaultDescription
upcomingstring"true"Return upcoming/active promotions (default behavior)
paststring-Set to "true" to return expired/past promotions with pagination
pageinteger1Page number (only with past=true)
pageSizeinteger10Results per page, max 100 (only with past=true)
startDatestring-Filter by date range start (YYYY-MM-DD)
endDatestring-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.

MethodPathAuthDescription
POST/chat/streamJWTStream 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.

MethodPathAuthDescription
GET/billing/statusJWTGet billing status (plan, subscription, credits)
GET/billing/invoicesJWTList paid invoices with PDF download links
POST/billing/checkoutJWT (Owner)Create Stripe Checkout session
POST/billing/portalJWT (Owner)Create Stripe Customer Portal session
PUT/billing/addonJWT (Owner)Add/change E-Commerce addon tier
DELETE/billing/addonJWT (Owner)Remove E-Commerce addon
POST/billing/webhookNoneStripe 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:

  • date is a Unix timestamp
  • amountPaid is in the smallest currency unit (cents)
  • pdfUrl links 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}/promotions now supports ?past=true&page=1&pageSize=10 for paginated past promotions
  • New endpoint: PATCH /accounts/{accountID}/promotions/{promotionID} for updating custom fields

v1.10.0 (2026-02-14)

  • Added mcc_id filter to GET /query/accounts — filter sub-accounts by MCC
  • Added search filter to GET /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 userId field in write requests for attribution tracking (defaults to "via API-Key")
  • New repo method SetAccountAssignees for 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.tenants with 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-enabled now writes to team_mcc_visibility junction table and recomputes accounts.sync_enabled
  • Sync service now respects sync_enabled when 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 viewer role to kunde with 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