{
  "openapi": "3.1.0",
  "info": {
    "title": "Nerve API",
    "description": "Nerve is the stateful AI operations layer by PNMP Innovations. Connect your AI tools to organizational intelligence — agent standups, daily briefings, company DNA, deal pipeline, and smart actions.",
    "version": "1.0.0",
    "termsOfService": "https://getnerve.ai/terms",
    "contact": {
      "name": "Patrick Hillstrom",
      "email": "patrick.hillstrom@pnmp-innovations.com",
      "url": "https://getnerve.ai/developers"
    },
    "license": {
      "name": "Proprietary"
    },
    "x-logo": {
      "url": "https://getnerve.ai/nerve-logo.png"
    }
  },
  "servers": [
    {
      "url": "https://getnerve.ai",
      "description": "Production"
    }
  ],
  "security": [
    { "BearerAuth": [] }
  ],
  "tags": [
    { "name": "Read", "description": "Read-only endpoints — available on Growth plans and above" },
    { "name": "Write", "description": "Write endpoints — available on Enterprise plans" },
    { "name": "Keys", "description": "API key management (requires Clerk session)" },
    { "name": "OAuth", "description": "OAuth 2.1 discovery and token management" }
  ],
  "paths": {
    "/api/mcp/agents": {
      "get": {
        "operationId": "getAgents",
        "summary": "Agent health dashboard",
        "description": "Returns status, summaries, and last-run timestamps for all 17 AI agents. Each agent reports health (green, stale, error, never_ran), a natural-language summary of its last output, and integration alerts (e.g. expired Google or Slack tokens).",
        "tags": ["Read"],
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Agent status array with health roll-up counts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "total": { "type": "integer", "description": "Total number of registered agents" },
                    "healthy": { "type": "integer", "description": "Count of agents with green health status" },
                    "stale": { "type": "integer", "description": "Count of agents that have not run in over 24 hours" },
                    "errors": { "type": "integer", "description": "Count of agents whose last run produced an error" },
                    "neverRan": { "type": "integer", "description": "Count of agents that have never executed" },
                    "agents": {
                      "type": "array",
                      "description": "Individual agent status objects",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string", "description": "Machine-readable agent identifier (e.g. 'standup', 'growth')" },
                          "name": { "type": "string", "description": "Human-readable agent name (e.g. 'Chief of Staff')" },
                          "category": { "type": "string", "description": "Agent category: ops, intelligence, growth, revenue, or product" },
                          "health": { "type": "string", "enum": ["green", "stale", "error", "never_ran"], "description": "Current health status based on last run time and error state" },
                          "generatedAt": { "type": "string", "format": "date-time", "description": "ISO 8601 timestamp of the agent's last successful run" },
                          "hoursAgo": { "type": "number", "description": "Hours since last run, null if never ran" },
                          "summary": { "type": "string", "description": "Natural-language summary of the agent's last output" },
                          "hasData": { "type": "boolean", "description": "Whether any stored data exists for this agent" }
                        }
                      }
                    },
                    "integrationAlerts": {
                      "type": "array",
                      "description": "Alerts for broken integrations (expired tokens, revoked access)",
                      "items": {
                        "type": "object",
                        "properties": {
                          "service": { "type": "string", "description": "Integration name (google, slack)" },
                          "severity": { "type": "string", "enum": ["critical", "warning"], "description": "Alert severity level" },
                          "message": { "type": "string", "description": "Human-readable description of the issue and how to fix it" },
                          "flaggedAt": { "type": "string", "format": "date-time", "description": "When the issue was first detected" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/standup": {
      "get": {
        "operationId": "getStandup",
        "summary": "Chief of Staff standup briefing",
        "description": "Pull the latest standup — morning, evening, or most recent. Includes agent statuses, metrics, interventions, and prioritized action items synthesized across all domains.",
        "tags": ["Read"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          {
            "name": "mode",
            "in": "query",
            "description": "Which standup to retrieve. 'morning' returns the AM briefing, 'evening' the EOD summary, 'latest' returns whichever ran most recently.",
            "schema": {
              "type": "string",
              "enum": ["morning", "evening", "latest"],
              "default": "latest"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Standup briefing with agent statuses and recommended actions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "mode": { "type": "string", "description": "The standup mode that was returned (morning, evening, or latest)" },
                    "generatedAt": { "type": "string", "format": "date-time", "description": "When this standup was generated" },
                    "briefing": { "type": "string", "description": "Natural-language standup briefing covering all domains" },
                    "agentStatuses": {
                      "type": "array",
                      "description": "Per-agent health and summary roll-up",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": { "type": "string", "description": "Agent name" },
                          "status": { "type": "string", "description": "Agent health status" },
                          "headline": { "type": "string", "description": "One-line summary of agent output" }
                        }
                      }
                    },
                    "metrics": {
                      "type": "object",
                      "description": "Key product and business metrics snapshot",
                      "properties": {
                        "dau": { "type": "integer", "description": "Daily active users" },
                        "wau": { "type": "integer", "description": "Weekly active users" },
                        "mrr": { "type": "number", "description": "Monthly recurring revenue in dollars" }
                      }
                    },
                    "interventions": {
                      "type": "array",
                      "description": "Action items requiring human attention, sorted by priority",
                      "items": {
                        "type": "object",
                        "properties": {
                          "title": { "type": "string", "description": "Short description of the intervention needed" },
                          "priority": { "type": "string", "description": "Urgency level: critical, high, medium, low" },
                          "agent": { "type": "string", "description": "Which agent surfaced this intervention" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/briefing": {
      "get": {
        "operationId": "getBriefing",
        "summary": "Personalized daily briefing",
        "description": "Your personalized daily briefing — AI recommendations, pending actions, meeting prep, draft emails, and an operational summary tailored to your role and recent activity.",
        "tags": ["Read"],
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Daily briefing with recommendations and pending actions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "briefing": { "type": "string", "description": "Full natural-language briefing text" },
                    "recommendations": {
                      "type": "array",
                      "description": "AI-generated recommendations for today, sorted by impact",
                      "items": { "type": "string" }
                    },
                    "pendingActions": {
                      "type": "array",
                      "description": "Action items awaiting human approval or completion",
                      "items": {
                        "type": "object",
                        "properties": {
                          "title": { "type": "string", "description": "Action item title" },
                          "priority": { "type": "string", "description": "Urgency: critical, high, medium, low" },
                          "source": { "type": "string", "description": "Which agent or workflow generated this action" }
                        }
                      }
                    },
                    "generatedAt": { "type": "string", "format": "date-time", "description": "When this briefing was generated" }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/suggestions": {
      "get": {
        "operationId": "getSuggestions",
        "summary": "Agent suggestions",
        "description": "Prioritized suggestions from Product, Growth, Revenue, Content, Corp Dev, Sales, and other agents. Filter by agent name to scope results.",
        "tags": ["Read"],
        "security": [{ "BearerAuth": [] }],
        "parameters": [
          {
            "name": "agent",
            "in": "query",
            "description": "Filter suggestions to a specific agent. Omit to return suggestions from all agents.",
            "schema": {
              "type": "string",
              "enum": ["product", "growth", "revenue", "content", "corpdev", "sales", "bdr", "compliance", "pulse"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Suggestions list sorted by priority and recency",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "suggestions": {
                      "type": "array",
                      "description": "Actionable suggestions generated by AI agents",
                      "items": {
                        "type": "object",
                        "properties": {
                          "agent": { "type": "string", "description": "Which agent generated this suggestion" },
                          "title": { "type": "string", "description": "Short headline for the suggestion" },
                          "detail": { "type": "string", "description": "Full context and reasoning behind the suggestion" },
                          "priority": { "type": "string", "description": "Priority ranking: critical, high, medium, low" },
                          "createdAt": { "type": "string", "format": "date-time", "description": "When the suggestion was generated" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/dna": {
      "get": {
        "operationId": "getCompanyDna",
        "summary": "Company DNA profile",
        "description": "Company archetype, strengths, weaknesses, pattern detection, and deal pipeline — your organizational fingerprint. Updated periodically by the Company DNA agent based on communication patterns, deals, and team behavior.",
        "tags": ["Read"],
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Company DNA with archetype analysis and pipeline summary",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "archetype": { "type": "string", "description": "Company archetype classification (e.g. 'Builder-Led Growth', 'Sales-Driven')" },
                    "strengths": {
                      "type": "array",
                      "description": "Identified organizational strengths based on communication and activity patterns",
                      "items": { "type": "string" }
                    },
                    "weaknesses": {
                      "type": "array",
                      "description": "Identified weaknesses or blind spots to address",
                      "items": { "type": "string" }
                    },
                    "patterns": {
                      "type": "array",
                      "description": "Behavioral patterns detected across email, calendar, and Slack",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": { "type": "string", "description": "Pattern name (e.g. 'Late-night commit spikes')" },
                          "insight": { "type": "string", "description": "What this pattern means for the business" }
                        }
                      }
                    },
                    "pipeline": {
                      "type": "array",
                      "description": "Active B2B deal pipeline summary",
                      "items": {
                        "type": "object",
                        "properties": {
                          "company": { "type": "string", "description": "Prospect company name" },
                          "stage": { "type": "string", "description": "Deal stage (lead, qualified, proposal, negotiation, closed)" },
                          "value": { "type": "number", "description": "Estimated deal value in dollars" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/keys": {
      "get": {
        "operationId": "listKeys",
        "summary": "List API keys",
        "description": "List your API keys. Requires Clerk session authentication (not Bearer token). Returns key hashes, names, scopes, and creation dates. Raw keys are never returned after initial creation.",
        "tags": ["Keys"],
        "responses": {
          "200": {
            "description": "Array of API key metadata (hashes, not raw keys)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "keys": {
                      "type": "array",
                      "description": "List of API key metadata objects",
                      "items": {
                        "type": "object",
                        "properties": {
                          "hash": { "type": "string", "description": "SHA-256 hash of the key (used for revocation)" },
                          "name": { "type": "string", "description": "User-assigned key name for identification" },
                          "scopes": {
                            "type": "array",
                            "description": "Authorized scopes: admin, agents, briefing, read",
                            "items": { "type": "string" }
                          },
                          "createdAt": { "type": "string", "format": "date-time", "description": "When the key was created" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      },
      "post": {
        "operationId": "createKey",
        "summary": "Create API key",
        "description": "Create a new API key with tier-appropriate scopes. Returns the raw key exactly once — save it immediately. The key is stored as a SHA-256 hash and cannot be retrieved again.",
        "tags": ["Keys"],
        "responses": {
          "200": {
            "description": "New API key (raw key shown once, then only the hash is stored)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "key": { "type": "string", "description": "Raw API key with nrv_ prefix. Only shown once — save it now." },
                    "hash": { "type": "string", "description": "SHA-256 hash of the key (used for management and revocation)" },
                    "scopes": {
                      "type": "array",
                      "description": "Scopes granted to this key based on your subscription tier",
                      "items": { "type": "string" }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      },
      "delete": {
        "operationId": "revokeKey",
        "summary": "Revoke an API key",
        "description": "Permanently revoke an API key by its SHA-256 hash. The key immediately stops working. This cannot be undone.",
        "tags": ["Keys"],
        "parameters": [
          {
            "name": "hash",
            "in": "query",
            "required": true,
            "description": "SHA-256 hash of the API key to revoke (from listKeys response)",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "Key successfully revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "description": "Whether the revocation succeeded" }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "404": {
            "description": "Key not found or already revoked",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/handoffs": {
      "post": {
        "operationId": "createHandoff",
        "summary": "Create agent-to-agent handoff",
        "description": "Route work between Growth, Revenue, Product, Content, and other agents. Handoffs are queued for execution and tracked in the agent coordination system.",
        "tags": ["Write"],
        "security": [{ "BearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["from", "to", "title"],
                "properties": {
                  "from": { "type": "string", "description": "Source agent identifier (e.g. 'growth', 'revenue', 'product')" },
                  "to": { "type": "string", "description": "Destination agent identifier that will receive and process the handoff" },
                  "title": { "type": "string", "description": "Short title describing the handoff task" },
                  "context": { "type": "string", "description": "Detailed context, background, and any data the receiving agent needs" },
                  "priority": { "type": "string", "enum": ["low", "medium", "high", "critical"], "description": "Urgency level — critical handoffs are processed immediately" },
                  "type": { "type": "string", "description": "Handoff type (e.g. 'research', 'draft', 'review', 'action')" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Handoff created and queued for processing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "description": "Whether the handoff was created successfully" },
                    "handoffId": { "type": "string", "description": "Unique identifier for tracking this handoff" }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/actions": {
      "post": {
        "operationId": "addAction",
        "summary": "Add task to admin queue",
        "description": "Add tasks and action items to your admin queue. Set priority, category, and recommendations. Actions surface in daily briefings and the standup.",
        "tags": ["Write"],
        "security": [{ "BearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["title"],
                "properties": {
                  "title": { "type": "string", "description": "Short title for the action item" },
                  "description": { "type": "string", "description": "Detailed description, context, or instructions for completing the action" },
                  "priority": { "type": "string", "enum": ["low", "medium", "high", "critical"], "description": "Urgency level — critical items surface at the top of briefings" },
                  "category": { "type": "string", "description": "Domain category (e.g. 'sales', 'product', 'ops', 'fundraising')" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Action created and added to the queue",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "description": "Whether the action was created successfully" },
                    "actionId": { "type": "string", "description": "Unique identifier for this action item" }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/contacts": {
      "post": {
        "operationId": "addContact",
        "summary": "Create or update CRM contact",
        "description": "Create or update contacts in your People CRM. Track relationships, next actions, deal associations, and interaction history. Upserts by email if a matching contact exists.",
        "tags": ["Write"],
        "security": [{ "BearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name"],
                "properties": {
                  "name": { "type": "string", "description": "Full name of the contact" },
                  "email": { "type": "string", "format": "email", "description": "Email address — used for deduplication (upsert)" },
                  "company": { "type": "string", "description": "Company or organization the contact belongs to" },
                  "role": { "type": "string", "description": "Job title or role at their company" },
                  "relationship": { "type": "string", "description": "Relationship status: contact, active, warm, cold, key" },
                  "notes": { "type": "string", "description": "Free-form notes about the contact, conversation history, or context" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Contact created or updated via upsert",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "description": "Whether the operation succeeded" },
                    "contactId": { "type": "string", "description": "Unique identifier for the contact" },
                    "action": { "type": "string", "description": "Whether the contact was 'created' or 'updated'" }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/mcp/feed": {
      "post": {
        "operationId": "logInsight",
        "summary": "Post to intelligence feed",
        "description": "Post insights to the shared intelligence feed. All agents read this on their next run — it's the system's cross-agent memory. Use this to inject strategic context, competitive intel, or market observations.",
        "tags": ["Write"],
        "security": [{ "BearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["title"],
                "properties": {
                  "title": { "type": "string", "description": "Headline for the insight (shown in feed and standup)" },
                  "detail": { "type": "string", "description": "Full context, reasoning, data points, or supporting evidence" },
                  "agent": { "type": "string", "description": "Which agent or source generated this insight (e.g. 'growth', 'revenue', 'manual')" },
                  "type": { "type": "string", "description": "Insight classification: insight, connection, learning, alert, action" },
                  "impact": { "type": "string", "enum": ["low", "medium", "high"], "description": "Expected impact level — high-impact insights surface first in briefings" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Insight posted to the intelligence feed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean", "description": "Whether the insight was posted successfully" },
                    "insightId": { "type": "string", "description": "Unique identifier for this insight" }
                  }
                }
              }
            }
          },
          "401": { "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth 2.1 access token). Get a key at https://getnerve.ai/dashboard/keys", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with error details per RFC 6750" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with required scope" }, "API-Version": { "schema": { "type": "string" }, "description": "API version" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.", "headers": { "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests per hour" }, "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in window" }, "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when quota resets" }, "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "operationId": "getOAuthMetadata",
        "summary": "OAuth 2.1 server metadata",
        "description": "RFC 8414 authorization server metadata. Returns endpoints, supported scopes, PKCE configuration, and grant types. Use this to bootstrap OAuth 2.1 client configuration automatically.",
        "tags": ["OAuth"],
        "security": [],
        "responses": {
          "200": {
            "description": "OAuth 2.1 authorization server metadata per RFC 8414",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "issuer": { "type": "string", "description": "Authorization server issuer URL (https://getnerve.ai)" },
                    "authorization_endpoint": { "type": "string", "description": "URL for authorization requests (/oauth/authorize)" },
                    "token_endpoint": { "type": "string", "description": "URL for token exchange (/oauth/token)" },
                    "registration_endpoint": { "type": "string", "description": "URL for dynamic client registration (/oauth/register)" },
                    "scopes_supported": {
                      "type": "array",
                      "description": "Available OAuth scopes: nerve:read, nerve:write, nerve:admin",
                      "items": { "type": "string" }
                    },
                    "code_challenge_methods_supported": {
                      "type": "array",
                      "description": "Supported PKCE code challenge methods (S256)",
                      "items": { "type": "string" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "operationId": "getResourceMetadata",
        "summary": "Protected resource metadata",
        "description": "RFC 9728 protected resource metadata. Tells MCP clients where the authorization server is and what scopes the resource accepts.",
        "tags": ["OAuth"],
        "security": [],
        "responses": {
          "200": {
            "description": "Protected resource metadata per RFC 9728",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "resource": { "type": "string", "description": "Resource server URL (https://getnerve.ai)" },
                    "authorization_servers": {
                      "type": "array",
                      "description": "List of authorization server URLs this resource trusts",
                      "items": { "type": "string" }
                    },
                    "scopes_supported": {
                      "type": "array",
                      "description": "Scopes the resource server accepts",
                      "items": { "type": "string" }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authenticate with a Nerve API key (nrv_ prefix) or an OAuth 2.1 access token. Create API keys at https://getnerve.ai/dashboard/keys. For OAuth 2.1, start at https://getnerve.ai/.well-known/oauth-authorization-server to discover endpoints."
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 with PKCE. Register a client dynamically at /oauth/register, authorize at /oauth/authorize (with S256 code challenge), and exchange codes at /oauth/token. Supports scopes: nerve:read (read-only), nerve:write (read + write), nerve:admin (full access). Access tokens expire in 1 hour; refresh tokens last 30 days.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://getnerve.ai/oauth/authorize",
            "tokenUrl": "https://getnerve.ai/oauth/token",
            "scopes": {
              "nerve:read": "Read-only access to standups, agents, briefings, DNA, suggestions",
              "nerve:write": "Read + write access including handoffs, actions, contacts, insights",
              "nerve:admin": "Full access including natural language query and admin endpoints"
            }
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing or invalid authentication. Provide a Bearer token (API key or OAuth access token). Get a key at https://getnerve.ai/dashboard/keys or use OAuth 2.1 via https://getnerve.ai/.well-known/oauth-authorization-server",
        "headers": {
          "WWW-Authenticate": {
            "schema": { "type": "string" },
            "description": "Bearer realm, error code, and human-readable description per RFC 6750"
          },
          "API-Version": {
            "schema": { "type": "string" },
            "description": "API version (currently 1.0.0)"
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "Forbidden": {
        "description": "Authenticated but insufficient permissions. Your API key's scopes do not include the required scope for this endpoint. Generate a new key with broader scopes at https://getnerve.ai/dashboard/keys",
        "headers": {
          "WWW-Authenticate": {
            "schema": { "type": "string" },
            "description": "Bearer realm with required scope per RFC 6750"
          },
          "API-Version": {
            "schema": { "type": "string" },
            "description": "API version (currently 1.0.0)"
          }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests. Back off per Retry-After header. Default quota: 600 requests/hour.",
        "headers": {
          "X-RateLimit-Limit": { "schema": { "type": "integer" }, "description": "Maximum requests allowed per hour" },
          "X-RateLimit-Remaining": { "schema": { "type": "integer" }, "description": "Remaining requests in the current window" },
          "X-RateLimit-Reset": { "schema": { "type": "integer" }, "description": "Unix timestamp when the quota resets" },
          "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds to wait before retrying" }
        },
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string", "description": "Machine-readable error code (e.g. 'unauthorized', 'invalid_token', 'insufficient_scope', 'rate_limited')" },
          "message": { "type": "string", "description": "Human-readable error description with guidance on how to resolve the issue" },
          "docs_url": { "type": "string", "format": "uri", "description": "Link to relevant documentation for troubleshooting" },
          "auth_url": { "type": "string", "format": "uri", "description": "OAuth 2.1 authorization server metadata URL (for auth errors)" },
          "required_scope": { "type": "string", "description": "The scope needed to access this endpoint (for 403 errors)" },
          "request_id": { "type": "string", "description": "Correlation ID for support requests" }
        }
      }
    }
  },
  "webhooks": {
    "briefingCompleted": {
      "post": {
        "operationId": "onBriefingCompleted",
        "summary": "Fired when a daily briefing finishes generating",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["event", "userId", "briefingId", "timestamp"],
                "properties": {
                  "event": { "type": "string", "enum": ["briefing.completed"], "description": "Event type identifier" },
                  "userId": { "type": "string", "description": "Clerk user ID the briefing was generated for" },
                  "briefingId": { "type": "string", "description": "Unique briefing identifier" },
                  "timestamp": { "type": "string", "format": "date-time", "description": "When the briefing completed" },
                  "summary": { "type": "string", "description": "Short summary of the briefing content" }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "Webhook acknowledged" } }
      }
    },
    "actionCreated": {
      "post": {
        "operationId": "onActionCreated",
        "summary": "Fired when a new action is logged against a contact or deal",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["event", "actionId", "timestamp"],
                "properties": {
                  "event": { "type": "string", "enum": ["action.created"], "description": "Event type identifier" },
                  "actionId": { "type": "string", "description": "Unique action identifier" },
                  "contactId": { "type": "string", "description": "Associated contact ID (if applicable)" },
                  "dealId": { "type": "string", "description": "Associated deal ID (if applicable)" },
                  "timestamp": { "type": "string", "format": "date-time", "description": "When the action was created" }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "Webhook acknowledged" } }
      }
    },
    "standupReady": {
      "post": {
        "operationId": "onStandupReady",
        "summary": "Fired when the morning agent standup is ready for delivery",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["event", "standupId", "timestamp"],
                "properties": {
                  "event": { "type": "string", "enum": ["standup.ready"], "description": "Event type identifier" },
                  "standupId": { "type": "string", "description": "Unique standup identifier" },
                  "timestamp": { "type": "string", "format": "date-time", "description": "When the standup was finalized" }
                }
              }
            }
          }
        },
        "responses": { "200": { "description": "Webhook acknowledged" } }
      }
    }
  },
  "externalDocs": {
    "description": "Nerve Developer Documentation",
    "url": "https://getnerve.ai/developers"
  }
}
