# AUTO-GENERATED by scripts/gen-openapi.ts — DO NOT EDIT BY HAND. # Source of truth: serverless.yml routes + handler middleware + types/schema.json. # Regenerate: `npm run openapi:gen` openapi: 3.0.3 info: title: KINETK Graph Service API version: 1.0.0 description: > Public HTTP API for the KINETK graph-service. Health/sync probe, precomputed narrative reads, and an async job queue for heavy intelligence work (`records`, `insights`, `campaign`). The legacy kind names (intelligence_records / intelligence_signals / campaign_brief / llm_context) are still accepted as deprecated aliases. Authentication: send your secret key in the `x-api-key` header on every request. Keys are issued from the billing dashboard and shown only once. Billing: async intelligence jobs are metered in credits (1 credit = $1.00). `POST /intelligence/jobs` requires an explicit `window` and returns an `estimated_cost` — an UPPER BOUND. Pricing is dynamic: you are charged the ACTUAL cost once the job completes (a query that returns fewer records than `limit` costs less), and the unused remainder of the reservation is released. If your balance can't cover a call you get `402` with a recommendation for how to fit your remaining budget. Every successful response carries `X-Kinetk-Credits-Used` and `X-Kinetk-Credits-Remaining` headers. Precomputed narrative/creator reads are free in V1. Cached job answers are charged at the full rate (no cache discount). contact: name: KINETK Engineering license: name: Proprietary servers: - url: https://api.kinetk.ai/graph description: Production. security: - ApiKeyAuth: [] paths: # /.well-known/oauth-protected-resource: # get: # operationId: oauthMetadata # summary: OauthMetadata # security: # - ApiKeyAuth: [] # responses: # "200": # description: Successful response # content: # application/json: # schema: # type: object # headers: # X-Kinetk-Credits-Used: # $ref: "#/components/headers/CreditsUsed" # X-Kinetk-Credits-Remaining: # $ref: "#/components/headers/CreditsRemaining" # default: # $ref: "#/components/responses/Error" /connect: post: operationId: mcp summary: Mcp security: - ApiKeyAuth: [] responses: "200": description: Successful response content: application/json: schema: type: object headers: X-Kinetk-Credits-Used: $ref: "#/components/headers/CreditsUsed" X-Kinetk-Credits-Remaining: $ref: "#/components/headers/CreditsRemaining" default: $ref: "#/components/responses/Error" /health: get: operationId: health summary: Health + sync-freshness probe description: Liveness probe reporting connectivity and database sync freshness. Returns `503` when the database is unreachable. security: - ApiKeyAuth: [] responses: "200": description: Successful response content: application/json: schema: $ref: "#/components/schemas/IHealthResponse" headers: X-Kinetk-Credits-Used: $ref: "#/components/headers/CreditsUsed" X-Kinetk-Credits-Remaining: $ref: "#/components/headers/CreditsRemaining" "503": description: Service degraded — the database is unreachable or a pipeline (sync, narratives, or content migration) is stale. Same body shape as the 200. content: application/json: schema: $ref: "#/components/schemas/IHealthResponse" default: $ref: "#/components/responses/Error" /intelligence/jobs: post: operationId: intelligenceJobsSubmit summary: Submit an async intelligence job description: > Submit a job for async execution. Request body is `{ kind, input }` discriminated by `kind`. Response shapes: - `200 + { fromCache: true, result, charged }` — identical recent job within the per-kind freshness window; cached result returned synchronously and charged at full rate (no cache discount). - `202 + { dedup: true }` — identical job currently queued/running; reuses the in-flight `jobId`. - `202 + { estimated_cost }` — new job accepted; the credits were reserved at the estimate. Poll `GET /intelligence/jobs/{id}`. - `402` — insufficient credits; body recommends how to fit your budget. For `records` / `insights`, `window` (in `input`) is REQUIRED — it drives the credit price (fresher windows cost more). `estimated_cost` is an upper bound; the final charge is computed from the records actually returned. Input validation is strict: any undeclared field, type mismatch, or out-of-enum value is rejected with `400` (nothing is silently stripped or coerced). security: - ApiKeyAuth: [] requestBody: required: true content: application/json: schema: oneOf: - $ref: "#/components/schemas/IQueryJobSubmitBody" # - $ref: "#/components/schemas/ICampaignJobSubmitBody" discriminator: propertyName: kind mapping: insights: "#/components/schemas/IQueryJobSubmitBody" records: "#/components/schemas/IQueryJobSubmitBody" # campaign: "#/components/schemas/ICampaignJobSubmitBody" responses: "200": description: Successful response content: application/json: schema: $ref: "#/components/schemas/IJobSubmitResponse" headers: X-Kinetk-Credits-Used: $ref: "#/components/headers/CreditsUsed" X-Kinetk-Credits-Remaining: $ref: "#/components/headers/CreditsRemaining" "402": description: Insufficient credits. The body reports the credits required vs available plus budget recommendations (max affordable limit, cheaper windows, top-up URL). content: application/json: schema: $ref: "#/components/schemas/IInsufficientCreditsResponse" default: $ref: "#/components/responses/Error" "/intelligence/jobs/{id}": get: operationId: intelligenceJobsStatus summary: Poll an async job — status + final result description: > Returns the job's current state. All states (`queued`, `running`, `succeeded`, `failed`) return `200`; `404` for an unknown `jobId`, `410` once the result has expired (~24h after completion). On `succeeded`, `result` usually carries the per-kind payload inline. When a result is too large to return inline, `result` is omitted and the response instead carries `resultStorage: "s3"` plus a short-lived presigned `resultUrl` (with `resultBytes` and `resultExpiresAt`) — fetch that URL directly to download the full payload, and re-poll for a fresh URL if it expires. Recommended polling cadence: every 2–5 seconds. Typical end-to-end run: 5–20 s. security: - ApiKeyAuth: [] parameters: - name: id in: path required: true schema: minLength: 1 type: string responses: "200": description: Successful response content: application/json: schema: $ref: "#/components/schemas/IJobStatusResponse" headers: X-Kinetk-Credits-Used: $ref: "#/components/headers/CreditsUsed" X-Kinetk-Credits-Remaining: $ref: "#/components/headers/CreditsRemaining" default: $ref: "#/components/responses/Error" /mcp: post: operationId: mcp summary: Mcp security: - ApiKeyAuth: [] responses: "200": description: Successful response content: application/json: schema: type: object headers: X-Kinetk-Credits-Used: $ref: "#/components/headers/CreditsUsed" X-Kinetk-Credits-Remaining: $ref: "#/components/headers/CreditsRemaining" default: $ref: "#/components/responses/Error" # "/narratives/{id}": # get: # operationId: narrativeDetail # summary: Drill into one precomputed narrative # description: Full evidence bundle for one narrative cluster — header, content # rows, top creators, per-platform breakdown, duplicate groups. # security: # - ApiKeyAuth: [] # parameters: # - name: id # in: path # required: true # schema: # minLength: 1 # type: string # responses: # "200": # description: Successful response # content: # application/json: # schema: # $ref: "#/components/schemas/INarrativeDetailResponse" # headers: # X-Kinetk-Credits-Used: # $ref: "#/components/headers/CreditsUsed" # X-Kinetk-Credits-Remaining: # $ref: "#/components/headers/CreditsRemaining" # default: # $ref: "#/components/responses/Error" # "/narratives/{id}/trajectory": # get: # operationId: narrativeTrajectory # summary: Narrative trajectory # security: # - ApiKeyAuth: [] # parameters: # - name: id # in: path # required: true # schema: # minLength: 1 # type: string # - name: limit # in: query # required: false # schema: # type: string # responses: # "200": # description: Successful response # content: # application/json: # schema: # $ref: "#/components/schemas/INarrativeTrajectoryResponse" # headers: # X-Kinetk-Credits-Used: # $ref: "#/components/headers/CreditsUsed" # X-Kinetk-Credits-Remaining: # $ref: "#/components/headers/CreditsRemaining" # default: # $ref: "#/components/responses/Error" # /narratives/search: # get: # operationId: narrativesSearch # summary: Filtered search over precomputed narratives # description: "Free-text search over precomputed narrative clusters, ranked by # relevance. For live retrieval, use `POST /intelligence/jobs` with `kind: # insights`." # security: # - ApiKeyAuth: [] # parameters: # - name: limit # in: query # required: false # schema: # type: string # - name: q # in: query # required: true # schema: # minLength: 1 # type: string # - name: window # in: query # required: false # schema: # enum: # - 30d # - 7d # type: string # responses: # "200": # description: Successful response # content: # application/json: # schema: # $ref: "#/components/schemas/INarrativeSearchResponse" # headers: # X-Kinetk-Credits-Used: # $ref: "#/components/headers/CreditsUsed" # X-Kinetk-Credits-Remaining: # $ref: "#/components/headers/CreditsRemaining" # default: # $ref: "#/components/responses/Error" # /narratives/trending: # get: # operationId: narrativesTrending # summary: Top precomputed narratives for a window # description: "Reads precomputed narrative clusters for a bounded window. For # live retrieval, submit `POST /intelligence/jobs` with `kind: insights`." # security: # - ApiKeyAuth: [] # parameters: # - name: limit # in: query # required: false # schema: # type: string # - name: window # in: query # required: false # schema: # enum: # - 30d # - 7d # type: string # responses: # "200": # description: Successful response # content: # application/json: # schema: # $ref: "#/components/schemas/ITrendingResponse" # headers: # X-Kinetk-Credits-Used: # $ref: "#/components/headers/CreditsUsed" # X-Kinetk-Credits-Remaining: # $ref: "#/components/headers/CreditsRemaining" # default: # $ref: "#/components/responses/Error" /usage: get: operationId: usage summary: Credit usage history for your account description: Newest-first ledger entries (top-ups, settlements, refunds) for the account the key belongs to. Paginate with `limit` + `cursor`; scope to a single key with `keyId`. security: - ApiKeyAuth: [] responses: "200": description: Successful response content: application/json: schema: $ref: "#/components/schemas/IUsageResponse" headers: X-Kinetk-Credits-Used: $ref: "#/components/headers/CreditsUsed" X-Kinetk-Credits-Remaining: $ref: "#/components/headers/CreditsRemaining" default: $ref: "#/components/responses/Error" components: securitySchemes: ApiKeyAuth: type: apiKey in: header name: x-api-key description: Customer secret key, required on every request. Validated natively by API Gateway; missing / invalid / revoked → 403. responses: Error: description: Error response content: application/json: schema: $ref: "#/components/schemas/ErrorResponse" schemas: ErrorResponse: type: object required: - error properties: error: type: string IBudgetRecommendations: additionalProperties: false properties: alternativeWindows: items: $ref: "#/components/schemas/IBudgetWindowOption" type: array maxLimitForWindow: type: number topUpUrl: type: string required: - maxLimitForWindow - topUpUrl type: object IBudgetWindowOption: additionalProperties: false properties: maxLimit: type: number window: $ref: "#/components/schemas/PublicJobWindow" required: - maxLimit - window type: object ICampaignBriefInput: additionalProperties: false properties: audience: type: string limit: type: number output: description: "Output mode: 'brief' (default) generates + saves a brief; 'context' returns the raw campaign-context bundle." enum: - brief - context type: string platforms: description: Platforms to filter by. Case-insensitive. items: enum: - instagram - pinterest - reddit - snapchat - tiktok - x type: string type: array query: description: The campaign topic/description (free text) — keyed by `query`, unified with records/insights. type: string tone: type: string window: $ref: "#/components/schemas/PublicJobWindow" required: - limit - query - window type: object ICampaignJobSubmitBody: additionalProperties: false properties: input: $ref: "#/components/schemas/ICampaignBriefInput" kind: enum: - campaign type: string required: - input - kind type: object IHealthResponse: additionalProperties: false properties: content: additionalProperties: false properties: isStale: type: boolean lastMigratedAt: type: string nullable: true minutesSinceMigration: type: number nullable: true required: - isStale - lastMigratedAt - minutesSinceMigration type: object db: enum: - connected - unreachable type: string dbError: type: string durationMs: type: number narratives: additionalProperties: false properties: isStale: type: boolean lastRunAt: type: string nullable: true minutesSinceLastRun: type: number nullable: true required: - isStale - lastRunAt - minutesSinceLastRun type: object stage: type: string status: enum: - error - ok type: string sync: additionalProperties: false properties: isStale: type: boolean lastCycle: $ref: "#/components/schemas/IHealthSyncLastCycle" nullable: true lastRunAt: type: string nullable: true minutesSinceLastRun: type: number nullable: true today: $ref: "#/components/schemas/IHealthSyncToday" nullable: true required: - isStale - lastCycle - lastRunAt - minutesSinceLastRun - today type: object timestamp: type: string required: - content - db - durationMs - narratives - stage - status - sync - timestamp type: object IHealthSyncLastCycle: additionalProperties: false properties: durationMs: type: number insertedCount: type: number processedCount: type: number required: - durationMs - insertedCount - processedCount type: object IHealthSyncToday: additionalProperties: false properties: insertedCount: type: number processedCount: type: number required: - insertedCount - processedCount type: object IInsightsJobResult: additionalProperties: false properties: attributeLifts: items: additionalProperties: false properties: lifts: items: additionalProperties: false properties: avgWith: type: number avgWithout: type: number countWith: type: number countWithout: type: number liftPct: type: number tag: type: string required: - avgWith - avgWithout - countWith - countWithout - liftPct - tag type: object type: array narrativeId: type: string narrativeLabel: type: string required: - lifts - narrativeId - narrativeLabel type: object type: array content: items: $ref: "#/components/schemas/PublicRankedContent" type: array contentGraph: additionalProperties: false properties: edges: items: additionalProperties: false properties: source: type: string target: type: string type: enum: - contains - creator_posted - semantic_similarity - tag_overlap - tagged_with type: string weight: type: number required: - source - target - type - weight type: object type: array nodes: items: additionalProperties: false properties: creatorId: type: number id: type: string label: type: string score: type: number type: enum: - content - creator - narrative - tag type: string required: - id - label - type type: object type: array required: - edges - nodes type: object creatorGraph: additionalProperties: false properties: edges: items: additionalProperties: false properties: source: type: string target: type: string type: enum: - contains - creator_posted - semantic_similarity - tag_overlap - tagged_with type: string weight: type: number required: - source - target - type - weight type: object type: array nodes: items: additionalProperties: false properties: creatorId: type: number id: type: string label: type: string score: type: number type: enum: - content - creator - narrative - tag type: string required: - id - label - type type: object type: array required: - edges - nodes type: object creators: items: additionalProperties: false properties: amplifierScore: type: number avgFinalScore: type: number contentCount: type: number creatorId: type: number nullable: true followerCount: type: number nullable: true platform: type: string totalEngagement: type: number required: - amplifierScore - avgFinalScore - contentCount - platform - totalEngagement type: object type: array generatedAt: type: string graph: additionalProperties: false properties: edges: items: additionalProperties: false properties: source: type: string target: type: string type: enum: - contains - creator_posted - semantic_similarity - tag_overlap - tagged_with type: string weight: type: number required: - source - target - type - weight type: object type: array nodes: items: additionalProperties: false properties: creatorId: type: number id: type: string label: type: string score: type: number type: enum: - content - creator - narrative - tag type: string required: - id - label - type type: object type: array required: - edges - nodes type: object insights: items: type: string type: array narrativeGraph: additionalProperties: false properties: edges: items: additionalProperties: false properties: source: type: string target: type: string type: enum: - contains - creator_posted - semantic_similarity - tag_overlap - tagged_with type: string weight: type: number required: - source - target - type - weight type: object type: array nodes: items: additionalProperties: false properties: creatorId: type: number id: type: string label: type: string score: type: number type: enum: - content - creator - narrative - tag type: string required: - id - label - type type: object type: array required: - edges - nodes type: object narrativeInsights: items: type: string type: array narrativeSaturation: items: additionalProperties: false properties: available: type: boolean coveredCount: type: number narrativeId: type: string narrativeLabel: type: string saturation: type: number nullable: true saturationCoverage: type: number required: - available - coveredCount - narrativeId - narrativeLabel - saturation - saturationCoverage type: object type: array narrativeSentiment: items: additionalProperties: false properties: dominantTone: type: string nullable: true membersWithSentiment: type: number narrativeId: type: string narrativeLabel: type: string netStance: type: number nullable: true stance: type: object properties: supportive: type: number critical: type: number neutral: type: number mixed: type: number required: - supportive - critical - neutral - mixed additionalProperties: false nullable: true stanceAvailable: type: boolean stanceCoverage: type: number stanceScored: type: number toneAvailable: type: boolean toneCoverage: type: number required: - dominantTone - membersWithSentiment - narrativeId - narrativeLabel - netStance - stance - stanceAvailable - stanceCoverage - stanceScored - toneAvailable - toneCoverage type: object type: array narratives: items: additionalProperties: false properties: contentCount: type: number contentUuids: items: type: string type: array creatorCount: type: number id: type: string label: type: string persistentLink: anyOf: - additionalProperties: false properties: acceleration: type: number nullable: true diffusion: type: number nullable: true emergingScore: type: number nullable: true label: type: string lifecycle: type: string nullable: true matchConfidence: enum: - high - medium type: string matchScore: type: number momentumScore: type: number nullable: true narrativeKey: type: string sentimentLabel: type: string nullable: true sentimentScore: type: number nullable: true sharedTerms: items: type: string type: array status: enum: - linked type: string trajectoryConfidence: type: string nullable: true velocity: type: number nullable: true required: - acceleration - diffusion - emergingScore - label - lifecycle - matchConfidence - matchScore - momentumScore - narrativeKey - sentimentLabel - sentimentScore - sharedTerms - status - trajectoryConfidence - velocity type: object - additionalProperties: false properties: status: enum: - net_new type: string required: - status type: object - additionalProperties: false properties: reason: enum: - insufficient_signal - no_persistent_generation type: string status: enum: - unavailable type: string required: - reason - status type: object platformCount: type: number queryRelevance: type: number representativeContent: items: $ref: "#/components/schemas/PublicRankedContent" type: array scoreBreakdown: additionalProperties: false properties: creatorDiversity: type: number engagementStrength: type: number platformSpread: type: number recencyStrength: type: number required: - creatorDiversity - engagementStrength - platformSpread - recencyStrength type: object summary: type: string topTags: items: type: string type: array topThemes: items: type: string type: array totalEngagement: type: number trendScore: type: number required: - contentCount - contentUuids - creatorCount - id - label - platformCount - representativeContent - scoreBreakdown - summary - topTags - topThemes - totalEngagement - trendScore type: object type: array platformOpportunities: items: additionalProperties: false properties: avgEngagement: type: number baselineEngagement: type: number contentCount: type: number creatorCount: type: number dominantPlatform: type: string engagementPremiumPct: type: number narrativeId: type: string narrativeLabel: type: string opportunity: type: string opportunityScore: type: number platformConcentration: type: number platformDistribution: type: object additionalProperties: type: number required: - avgEngagement - baselineEngagement - contentCount - creatorCount - dominantPlatform - engagementPremiumPct - narrativeId - narrativeLabel - opportunity - opportunityScore - platformConcentration - platformDistribution type: object type: array query: type: string tagCombinations: items: additionalProperties: false properties: avgEngagementA: type: number avgEngagementB: type: number avgEngagementTogether: type: number combination: type: string combinationLiftPct: type: number cooccurrence: type: number tagA: type: string tagB: type: string required: - avgEngagementA - avgEngagementB - avgEngagementTogether - combination - combinationLiftPct - cooccurrence - tagA - tagB type: object type: array tagGraph: additionalProperties: false properties: edges: items: additionalProperties: false properties: source: type: string target: type: string type: enum: - contains - creator_posted - semantic_similarity - tag_overlap - tagged_with type: string weight: type: number required: - source - target - type - weight type: object type: array nodes: items: additionalProperties: false properties: creatorId: type: number id: type: string label: type: string score: type: number type: enum: - content - creator - narrative - tag type: string required: - id - label - type type: object type: array required: - edges - nodes type: object tagInsights: items: type: string type: array tagNarrativeMap: items: additionalProperties: false properties: avgEngagement: type: number dominantNarrativeId: type: string dominantNarrativeLabel: type: string engagementPremiumPct: type: number exclusivity: type: number frequency: type: number platformCount: type: number role: enum: - Bridge - Shared - Signature type: string tag: type: string required: - avgEngagement - dominantNarrativeId - dominantNarrativeLabel - engagementPremiumPct - exclusivity - frequency - platformCount - role - tag type: object type: array tagSignals: items: additionalProperties: false properties: avgEngagement: type: number baselineEngagement: type: number count: type: number dominantPlatform: type: string engagementPremiumPct: type: number opportunityScore: type: number platformConcentration: type: number platformDistribution: type: object additionalProperties: type: number saturation: type: number nullable: true saturationCoverage: type: number tag: type: string whitespaceScore: type: number nullable: true required: - avgEngagement - baselineEngagement - count - dominantPlatform - engagementPremiumPct - opportunityScore - platformConcentration - platformDistribution - saturation - saturationCoverage - tag - whitespaceScore type: object type: array themeSignals: additionalProperties: false properties: available: type: boolean coverage: type: number coverageFloor: type: number coveredCount: type: number signals: items: additionalProperties: false properties: avgEngagement: type: number baselineEngagement: type: number count: type: number dominantPlatform: type: string engagementPremiumPct: type: number opportunityScore: type: number platformConcentration: type: number platformDistribution: type: object additionalProperties: type: number saturation: type: number nullable: true saturationCoverage: type: number theme: type: string whitespaceScore: type: number nullable: true required: - avgEngagement - baselineEngagement - count - dominantPlatform - engagementPremiumPct - opportunityScore - platformConcentration - platformDistribution - saturation - saturationCoverage - theme - whitespaceScore type: object type: array required: - available - coverage - coverageFloor - coveredCount - signals type: object topTags: items: additionalProperties: false properties: avgEngagement: type: number engagementPremiumPct: type: number frequency: type: number momentumScore: type: number platformCount: type: number signalClass: type: string tag: type: string required: - avgEngagement - engagementPremiumPct - frequency - momentumScore - platformCount - signalClass - tag type: object type: array type: enum: - kinetk.query_intelligence.insights.v1 type: string window: $ref: "#/components/schemas/NarrativeWindow" required: - attributeLifts - content - contentGraph - creatorGraph - creators - generatedAt - graph - narrativeGraph - narrativeSaturation - narrativeSentiment - narratives - platformOpportunities - query - tagCombinations - tagGraph - tagNarrativeMap - tagSignals - themeSignals - topTags - type - window type: object IInsufficientCreditsResponse: additionalProperties: false properties: credits_available: type: number credits_required: type: number error: enum: - insufficient_credits type: string recommendations: $ref: "#/components/schemas/IBudgetRecommendations" tier: description: "Pricing tier of the requested kind: 1 = per-record, 2 = per-signal." enum: - 1 - 2 type: number window: $ref: "#/components/schemas/PublicJobWindow" required: - credits_available - credits_required - error - recommendations - tier - window type: object IJobStatusResponse: additionalProperties: false properties: completedAt: type: number error: type: string jobId: type: string kind: $ref: "#/components/schemas/JobKind" result: anyOf: - $ref: "#/components/schemas/IRecordsJobResult" - $ref: "#/components/schemas/IInsightsJobResult" resultBytes: description: Size of the stored result in bytes (present alongside resultUrl). type: number resultExpiresAt: description: ISO-8601 expiry of resultUrl (clamped to the job's own retention). type: string resultStorage: enum: - s3 description: >- Set to "s3" when the result was too large to return inline; in that case `result` is omitted and `resultUrl` holds a short-lived presigned download URL instead. Fetch the URL directly; re-poll for a fresh one after it expires (see resultExpiresAt). type: string resultUrl: description: Short-lived presigned GET URL for a large result (present iff resultStorage === "s3"). type: string startedAt: type: number status: $ref: "#/components/schemas/JobStatus" submittedAt: type: number required: - jobId - kind - status - submittedAt type: object IJobSubmitResponse: additionalProperties: false properties: dedup: type: boolean fromCache: type: boolean jobId: type: string result: anyOf: - $ref: "#/components/schemas/IRecordsJobResult" - $ref: "#/components/schemas/IInsightsJobResult" resultBytes: description: Size of the stored result in bytes (present alongside resultUrl). type: number resultExpiresAt: description: ISO-8601 expiry of resultUrl (clamped to the job's own retention). type: string resultStorage: enum: - s3 description: >- Set to "s3" when the result was too large to return inline; in that case `result` is omitted and `resultUrl` holds a short-lived presigned download URL instead. Fetch the URL directly; re-poll for a fresh one after it expires (see resultExpiresAt). type: string resultUrl: description: Short-lived presigned GET URL for a large result (present iff resultStorage === "s3"). type: string status: $ref: "#/components/schemas/JobStatus" statusUrl: type: string required: - jobId - status type: object INarrativeContentItem: additionalProperties: false properties: comment_count: type: number nullable: true description: type: string nullable: true is_representative: type: boolean like_count: type: number nullable: true platform: type: string published_at: type: string nullable: true relevance_score: type: number share_count: type: number nullable: true tags: items: type: string type: array title: type: string nullable: true uuid: type: string view_count: type: number nullable: true required: - is_representative - platform - relevance_score - tags - uuid type: object INarrativeCreatorMetric: additionalProperties: false properties: amplifier_score: type: number content_count: type: number first_seen_at: type: string follower_count: type: number nullable: true id: type: string platform: type: string total_engagement: type: string required: - amplifier_score - content_count - first_seen_at - id - platform - total_engagement type: object INarrativeDetailResponse: additionalProperties: false properties: content: items: $ref: "#/components/schemas/INarrativeContentItem" type: array creators: items: $ref: "#/components/schemas/INarrativeCreatorMetric" type: array duplicateGroups: items: $ref: "#/components/schemas/INarrativeDuplicateGroup" type: array narrative: $ref: "#/components/schemas/INarrativeSummary" platformBreakdown: items: $ref: "#/components/schemas/INarrativePlatformBreakdown" type: array required: - content - creators - duplicateGroups - narrative - platformBreakdown type: object INarrativeDuplicateGroup: additionalProperties: false properties: canonical_content_uuid: type: string confidence: type: number id: type: string members: items: type: string type: array required: - canonical_content_uuid - confidence - id - members type: object INarrativePlatformBreakdown: additionalProperties: false properties: content_count: type: number platform: type: string total_engagement: type: string required: - content_count - platform - total_engagement type: object INarrativeScoreBreakdown: additionalProperties: false properties: clustering_method: type: string content_count: type: number creator_count: type: number pair_count: type: number platform_count: type: number seed_tag: type: string total_engagement: type: number required: - content_count - creator_count - platform_count - total_engagement type: object INarrativeSearchResponse: additionalProperties: false properties: narratives: items: $ref: "#/components/schemas/INarrativeSummary" type: array query: type: string window: enum: - 30d - 7d type: string required: - narratives - query - window type: object INarrativeSentimentBreakdown: additionalProperties: false properties: coverage: type: number dominant_tone: type: string nullable: true stance: additionalProperties: false properties: critical: type: number mixed: type: number neutral: type: number supportive: type: number required: - critical - mixed - neutral - supportive type: object nullable: true stance_coverage: type: number type: object INarrativeSummary: additionalProperties: false properties: acceleration: type: number nullable: true computed_at: type: string content_count: type: number creator_count: type: number diffusion: type: number nullable: true emerging_score: type: number id: type: string label: type: string lifecycle: type: string nullable: true momentum_score: type: number narrative_key: type: string nullable: true overlap_count: type: number platform_count: type: number representative_content_uuid: type: string nullable: true score_breakdown: $ref: "#/components/schemas/INarrativeScoreBreakdown" sentiment_breakdown: $ref: "#/components/schemas/INarrativeSentimentBreakdown" nullable: true sentiment_label: type: string nullable: true sentiment_score: type: number nullable: true summary: type: string text_rank: type: number top_tags: items: type: string type: array total_engagement: type: string trajectory_confidence: type: string nullable: true velocity: type: number nullable: true window_end: type: string window_key: enum: - 30d - 7d type: string window_start: type: string required: - computed_at - content_count - creator_count - emerging_score - id - label - momentum_score - platform_count - score_breakdown - summary - top_tags - total_engagement - window_end - window_key - window_start type: object INarrativeTrajectoryPoint: additionalProperties: false properties: acceleration: type: number nullable: true computed_at: type: string content_count: type: number creator_count: type: number diffusion: type: number nullable: true emerging_score: type: number label: type: string lifecycle: type: string nullable: true momentum_score: type: number platform_count: type: number sentiment_breakdown: $ref: "#/components/schemas/INarrativeSentimentBreakdown" nullable: true top_tags: items: type: string type: array total_engagement: type: string velocity: type: number nullable: true required: - computed_at - content_count - creator_count - emerging_score - label - momentum_score - platform_count - top_tags - total_engagement type: object INarrativeTrajectoryResponse: additionalProperties: false properties: id: type: string narrativeKey: type: string nullable: true trajectory: items: $ref: "#/components/schemas/INarrativeTrajectoryPoint" type: array window: enum: - 30d - 7d type: string required: - id - narrativeKey - trajectory - window type: object IQueryIntelligenceInput: additionalProperties: false properties: includeSignals: description: Include the LLM insight prose arrays in the result (for insights). type: boolean limit: type: number platforms: description: Platforms to filter by. Case-insensitive. items: enum: - instagram - pinterest - reddit - snapchat - tiktok - x type: string type: array query: type: string window: $ref: "#/components/schemas/PublicJobWindow" required: - limit - query - window type: object IQueryJobSubmitBody: additionalProperties: false properties: input: $ref: "#/components/schemas/IQueryIntelligenceInput" kind: enum: - insights - records type: string required: - input - kind type: object IRecordsJobResult: additionalProperties: false properties: content: items: $ref: "#/components/schemas/PublicRankedContent" type: array generatedAt: type: string graph: additionalProperties: false properties: edges: items: additionalProperties: false properties: source: type: string target: type: string type: enum: - contains - creator_posted - semantic_similarity - tag_overlap - tagged_with type: string weight: type: number required: - source - target - type - weight type: object type: array nodes: items: additionalProperties: false properties: creatorId: type: number id: type: string label: type: string score: type: number type: enum: - content - creator - narrative - tag type: string required: - id - label - type type: object type: array required: - edges - nodes type: object query: type: string type: enum: - kinetk.query_intelligence.record.v1 type: string window: $ref: "#/components/schemas/NarrativeWindow" required: - content - generatedAt - graph - query - type - window type: object ITrendingResponse: additionalProperties: false properties: narratives: items: $ref: "#/components/schemas/INarrativeSummary" type: array window: enum: - 30d - 7d type: string required: - narratives - window type: object IUsageEntry: additionalProperties: false properties: balanceAfter: type: number credits: type: number jobId: type: string keyId: type: string kind: enum: # - campaign - insights - records type: string occurredAt: type: string reason: type: string stripeDisputeId: type: string stripePaymentIntentId: type: string stripeRefundId: type: string txnId: type: string type: enum: - refund - reserve - reversal - settle - topup type: string window: type: string required: - credits - occurredAt - txnId - type type: object IUsageResponse: additionalProperties: false properties: accountId: type: string keyId: type: string nextCursor: type: string usage: items: $ref: "#/components/schemas/IUsageEntry" type: array required: - accountId - usage type: object JobKind: enum: # - campaign - insights - records type: string JobStatus: enum: - failed - queued - running - succeeded type: string NarrativeWindow: enum: - 30d - 7d - all type: string PublicEnrichment: additionalProperties: false properties: aestheticStyle: items: type: string type: array attributeConfidence: type: number nullable: true brandProducts: items: type: string type: array coverage: additionalProperties: false properties: attributes: type: boolean novelty: type: boolean sentiment: type: boolean required: - attributes - novelty - sentiment type: object emotionMood: items: type: string type: array noveltyScore: type: number nullable: true saturationScore: type: number nullable: true themes: items: type: string type: array tone: type: string nullable: true toneConfidence: type: number nullable: true required: - aestheticStyle - attributeConfidence - brandProducts - coverage - emotionMood - noveltyScore - saturationScore - themes - tone - toneConfidence type: object PublicJobWindow: enum: - 30d - 7d - all type: string PublicRankedContent: additionalProperties: false properties: authorReach: type: number commentCount: type: number contentType: type: string nullable: true creatorId: type: number nullable: true description: type: string nullable: true engagementDepth: type: number engagementScore: type: number enrichment: $ref: "#/components/schemas/PublicEnrichment" exampleRankingScore: type: number followerCount: type: number nullable: true likeCount: type: number platform: type: string nullable: true publishedAt: type: string nullable: true rawSimilarity: type: number recencyScore: type: number relevance: type: number rrfScore: type: number shareCount: type: number similarity: type: number subjectMatch: type: boolean tags: items: type: string type: array textRerankScore: type: number nullable: true title: type: string nullable: true uuid: type: string viewCount: type: number required: - authorReach - commentCount - engagementDepth - engagementScore - exampleRankingScore - likeCount - rawSimilarity - recencyScore - rrfScore - shareCount - similarity - tags - uuid - viewCount type: object headers: CreditsUsed: description: Credits consumed by this call (reserved estimate on a 202; actual once settled). schema: type: number example: 4 CreditsRemaining: description: Account credit balance remaining after this call. schema: type: number example: 996