docs: define AI growth report API contract
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user