docs: define AI growth report API contract

This commit is contained in:
2026-08-21 00:29:25 +03:30
parent 027dffb59e
commit 1d8d4edf92

View File

@@ -578,6 +578,66 @@ paths:
'504':
$ref: '#/components/responses/ExportTimeout'
/analytics/growth-reports:
post:
tags: [AI growth analyst]
operationId: createGrowthReport
summary: Create or reuse a growth report
parameters:
- $ref: '#/components/parameters/IdempotencyKeyHeader'
- $ref: '#/components/parameters/CsrfTokenHeader'
- $ref: '#/components/parameters/OriginHeader'
- $ref: '#/components/parameters/RequestIdHeader'
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/CreateGrowthReportRequest'}
responses:
'200': {description: Matching durable report reused., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthReport'}}}}
'202': {description: Report accepted for generation., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthReport'}}}}
'401': {$ref: '#/components/responses/Unauthenticated'}
'403': {$ref: '#/components/responses/Forbidden'}
'409': {$ref: '#/components/responses/Conflict'}
'422': {$ref: '#/components/responses/ValidationFailed'}
'429': {$ref: '#/components/responses/RateLimited'}
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
/analytics/growth-reports/latest:
get:
tags: [AI growth analyst]
operationId: getLatestGrowthReport
parameters:
- {name: terminalId, in: query, required: false, schema: {type: string}}
- $ref: '#/components/parameters/RequestIdHeader'
responses:
'200': {description: Latest successful report for the authorized scope., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthReport'}}}}
'401': {$ref: '#/components/responses/Unauthenticated'}
'404': {$ref: '#/components/responses/ResourceNotFound'}
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
/analytics/growth-reports/{reportId}:
get:
tags: [AI growth analyst]
operationId: getGrowthReport
parameters:
- {name: reportId, in: path, required: true, schema: {type: string, pattern: '^growth_[a-f0-9]{24}$'}}
- $ref: '#/components/parameters/RequestIdHeader'
responses:
'200': {description: Authorized report snapshot., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthReport'}}}}
'401': {$ref: '#/components/responses/Unauthenticated'}
'404': {$ref: '#/components/responses/ResourceNotFound'}
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
/analytics/growth-reports/{reportId}/events:
get:
tags: [AI growth analyst]
operationId: streamGrowthReportEvents
parameters:
- {name: reportId, in: path, required: true, schema: {type: string}}
- {name: Last-Event-ID, in: header, required: false, schema: {type: string}}
responses:
'200': {description: Stable-id report snapshots and heartbeats., content: {text/event-stream: {schema: {type: string}}}}
'401': {$ref: '#/components/responses/Unauthenticated'}
'404': {$ref: '#/components/responses/ResourceNotFound'}
components:
securitySchemes:
merchantSession:
@@ -943,6 +1003,159 @@ components:
$ref: '#/components/schemas/Problem'
schemas:
CreateGrowthReportRequest:
type: object
additionalProperties: false
properties:
terminalId: {type: string, minLength: 1, maxLength: 128}
refresh: {type: boolean, default: false}
GrowthRange:
type: object
additionalProperties: false
required: [p10, p50, p90]
properties:
p10: {type: integer, format: int64, minimum: 0}
p50: {type: integer, format: int64, minimum: 0}
p90: {type: integer, format: int64, minimum: 0}
GrowthForecastPoint:
type: object
additionalProperties: false
required: [date, baselineSessions, baselineAmountRial, paidSessions, paidAmountRial]
properties:
date: {type: string, format: date-time}
baselineSessions: {type: integer, format: int64, minimum: 0}
baselineAmountRial: {type: integer, format: int64, minimum: 0}
paidSessions: {$ref: '#/components/schemas/GrowthRange'}
paidAmountRial: {$ref: '#/components/schemas/GrowthRange'}
eventIds: {type: array, items: {type: string}}
GrowthForecast:
type: object
additionalProperties: false
required: [startDate, horizonDays, confidence, points, backtest]
properties:
startDate: {type: string, format: date-time}
horizonDays: {type: integer, enum: [90]}
confidence: {type: string, enum: [HIGH, MEDIUM, INSUFFICIENT_DATA]}
suppressionReason: {type: string}
points: {type: array, maxItems: 90, items: {$ref: '#/components/schemas/GrowthForecastPoint'}}
backtest:
type: object
additionalProperties: false
required: [origins, sessionMapeBps, amountMapeBps, intervalCoverageBps]
properties:
origins: {type: integer, minimum: 0}
sessionMapeBps: {type: integer, format: int64, minimum: 0}
amountMapeBps: {type: integer, format: int64, minimum: 0}
intervalCoverageBps: {type: integer, format: int64, minimum: 0, maximum: 10000}
GrowthHistoricalWin:
type: object
additionalProperties: true
required: [evidenceId, eventId, eventTitleFa, startDate, endDate, materialWin]
properties:
evidenceId: {type: string}
eventId: {type: string}
eventTitleFa: {type: string}
startDate: {type: string, format: date-time}
endDate: {type: string, format: date-time}
eligible: {type: boolean}
suppressionReason: {type: string}
observationCount: {type: integer}
baselineSessionCount: {type: integer, format: int64}
baselinePaidSessions: {type: integer, format: int64}
baselineAmountRial: {type: integer, format: int64}
actualSessionCount: {type: integer, format: int64}
actualPaidSessions: {type: integer, format: int64}
actualAmountRial: {type: integer, format: int64}
sessionUpliftBps: {type: integer, format: int64}
paidSessionUpliftBps: {type: integer, format: int64}
amountUpliftBps: {type: integer, format: int64}
materialWin: {type: boolean}
materialDecline: {type: boolean}
GrowthOpportunity:
type: object
additionalProperties: false
required: [evidenceId, eventId, eventTitleFa, date, similarityBps, expectedSessions, expectedAmountRial, historicalEvidenceId]
properties:
evidenceId: {type: string}
eventId: {type: string}
eventTitleFa: {type: string}
date: {type: string, format: date-time}
similarityBps: {type: integer, format: int64, minimum: 6000, maximum: 10000}
expectedSessions: {$ref: '#/components/schemas/GrowthRange'}
expectedAmountRial: {$ref: '#/components/schemas/GrowthRange'}
historicalEvidenceId: {type: string}
GrowthRisk:
type: object
additionalProperties: false
required: [evidenceId, date, sessionDeclineBps, amountDeclineBps, expectedSessions, expectedAmountRial]
properties:
evidenceId: {type: string}
date: {type: string, format: date-time}
endDate: {type: string, format: date-time}
sessionDeclineBps: {type: integer, format: int64, minimum: 2000}
amountDeclineBps: {type: integer, format: int64, minimum: 2000}
expectedSessions: {$ref: '#/components/schemas/GrowthRange'}
expectedAmountRial: {$ref: '#/components/schemas/GrowthRange'}
GrowthPeer:
type: object
additionalProperties: false
required: [state, eligiblePeerCount, combinedPeerSessionCount, medianPaidSessions, percentileBps]
properties:
state: {type: string, enum: [READY, SUPPRESSED]}
reason: {type: string}
eligiblePeerCount: {type: integer, minimum: 0}
combinedPeerSessionCount: {type: integer, format: int64, minimum: 0}
medianPaidSessions: {type: integer, format: int64, minimum: 0}
percentileBps: {type: integer, format: int64, minimum: 0, maximum: 10000}
GrowthCampaignBrief:
type: object
additionalProperties: false
required: [headline, interpretation, offerSuggestion, messageSuggestion, preparationAction, limitation, evidenceIds]
properties:
headline: {type: string}
interpretation: {type: string}
offerSuggestion: {type: string}
messageSuggestion: {type: string}
preparationAction: {type: string}
limitation: {type: string}
evidenceIds: {type: array, minItems: 1, items: {type: string}}
GrowthEvidence:
type: object
additionalProperties: false
required: [forecast, historicalWins, opportunities, risks, fallbackBriefs]
properties:
forecast: {$ref: '#/components/schemas/GrowthForecast'}
historicalWins: {type: array, items: {$ref: '#/components/schemas/GrowthHistoricalWin'}}
opportunities: {type: array, maxItems: 5, items: {$ref: '#/components/schemas/GrowthOpportunity'}}
risks: {type: array, maxItems: 3, items: {$ref: '#/components/schemas/GrowthRisk'}}
peer: {$ref: '#/components/schemas/GrowthPeer'}
fallbackBriefs: {type: array, items: {$ref: '#/components/schemas/GrowthCampaignBrief'}}
GrowthReport:
type: object
additionalProperties: false
required: [reportId, status, scope, horizonDays, deterministicEvidence, cached, stale, nextRefreshAt, createdAt, updatedAt, eventsUrl]
properties:
reportId: {type: string}
status: {type: string, enum: [QUEUED, ANALYZING, GENERATING, READY, PARTIAL, FAILED]}
scope:
type: object
additionalProperties: false
properties: {terminalId: {type: [string, 'null']}}
horizonDays: {type: integer, enum: [90]}
forecastStartDate: {type: string, format: date-time}
deterministicEvidence: {$ref: '#/components/schemas/GrowthEvidence'}
aiCopy:
type: object
additionalProperties: false
required: [briefs]
properties: {briefs: {type: array, maxItems: 5, items: {$ref: '#/components/schemas/GrowthCampaignBrief'}}}
failureCode: {type: string}
cached: {type: boolean}
stale: {type: boolean}
nextRefreshAt: {type: string, format: date-time}
createdAt: {type: string, format: date-time}
updatedAt: {type: string, format: date-time}
eventsUrl: {type: string, format: uri-reference}
LoginRequest:
type: object
additionalProperties: false