fix: deliver validated AI insight responses
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: ZarinPal Merchant Analytics API
|
||||
version: 1.1.0
|
||||
version: 1.2.0
|
||||
summary: Contract-first API for authenticated merchant analytics and growth reports.
|
||||
description: |
|
||||
Approved analytics and AI growth-report interface. This document is the API source of truth; generated
|
||||
@@ -20,6 +20,7 @@ tags:
|
||||
- name: Reporting periods
|
||||
- name: Analytics runs
|
||||
- name: Analytics details
|
||||
- name: Growth coach
|
||||
security:
|
||||
- merchantSession: []
|
||||
paths:
|
||||
@@ -646,6 +647,7 @@ paths:
|
||||
parameters:
|
||||
- {name: module, in: path, required: true, schema: {$ref: '#/components/schemas/AIInsightModule'}}
|
||||
- {name: terminalId, in: query, required: false, schema: {type: string, maxLength: 128}}
|
||||
- {name: periodId, in: query, required: false, description: Used only by the transactions module to match the selected reporting period., schema: {type: string, maxLength: 128}}
|
||||
- $ref: '#/components/parameters/RequestIdHeader'
|
||||
responses:
|
||||
'200': {description: Latest ready or deterministic-partial snapshot., content: {application/json: {schema: {$ref: '#/components/schemas/AIInsight'}}}}
|
||||
@@ -676,6 +678,30 @@ paths:
|
||||
'422': {$ref: '#/components/responses/ValidationFailed'}
|
||||
'429': {$ref: '#/components/responses/RateLimited'}
|
||||
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
|
||||
/analytics/ai-insights/{module}/sections/{sectionId}/refreshes:
|
||||
post:
|
||||
tags: [AI page insights]
|
||||
operationId: refreshAIInsightSection
|
||||
summary: Refresh one independently persisted AI narrative section
|
||||
parameters:
|
||||
- {name: module, in: path, required: true, schema: {$ref: '#/components/schemas/AIInsightModule'}}
|
||||
- {name: sectionId, in: path, required: true, schema: {$ref: '#/components/schemas/AIInsightSection'}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
- $ref: '#/components/parameters/OriginHeader'
|
||||
requestBody:
|
||||
required: true
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/AIInsightRefreshRequest'}}}
|
||||
responses:
|
||||
'200': {description: Idempotent job reused., content: {application/json: {schema: {$ref: '#/components/schemas/AIInsightJob'}}}}
|
||||
'202': {description: Section refresh accepted., content: {application/json: {schema: {$ref: '#/components/schemas/AIInsightJob'}}}}
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'403': {$ref: '#/components/responses/Forbidden'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
'422': {$ref: '#/components/responses/ValidationFailed'}
|
||||
'429': {$ref: '#/components/responses/RateLimited'}
|
||||
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
|
||||
/analytics/ai-insight-refreshes/{jobId}:
|
||||
get:
|
||||
tags: [AI page insights]
|
||||
@@ -699,6 +725,159 @@ paths:
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
|
||||
/growth-coach:
|
||||
get:
|
||||
tags: [Growth coach]
|
||||
operationId: getGrowthCoachDashboard
|
||||
summary: Return a terminal coach workspace or an all-terminal rollup
|
||||
parameters:
|
||||
- {name: terminalId, in: query, required: false, schema: {type: string, maxLength: 128}}
|
||||
responses:
|
||||
'200': {description: Persisted coach state and deterministic progress., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthCoachDashboard'}}}}
|
||||
'401': {$ref: '#/components/responses/Unauthenticated'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
'503': {$ref: '#/components/responses/AnalyticsUnavailable'}
|
||||
/growth-coach/terminals/{terminalId}/profile:
|
||||
get:
|
||||
tags: [Growth coach]
|
||||
operationId: getGrowthCoachProfile
|
||||
parameters:
|
||||
- {name: terminalId, in: path, required: true, schema: {type: string, maxLength: 128}}
|
||||
responses:
|
||||
'200': {description: Current profile version., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthCoachProfile'}}}}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
put:
|
||||
tags: [Growth coach]
|
||||
operationId: putGrowthCoachProfile
|
||||
parameters:
|
||||
- {name: terminalId, in: path, required: true, schema: {type: string, maxLength: 128}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
requestBody:
|
||||
required: true
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/GrowthCoachProfileInput'}}}
|
||||
responses:
|
||||
'201': {description: New profile version and generation jobs., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthCoachProfileResult'}}}}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
'422': {$ref: '#/components/responses/ValidationFailed'}
|
||||
/growth-coach/terminals/{terminalId}/refreshes:
|
||||
post:
|
||||
tags: [Growth coach]
|
||||
operationId: refreshGrowthCoach
|
||||
parameters:
|
||||
- {name: terminalId, in: path, required: true, schema: {type: string, maxLength: 128}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
requestBody:
|
||||
required: true
|
||||
content: {application/json: {schema: {$ref: '#/components/schemas/GrowthCoachRefreshInput'}}}
|
||||
responses:
|
||||
'202': {description: Cadence-scoped coach refresh queued., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthCoachJob'}}}}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
'422': {$ref: '#/components/responses/ValidationFailed'}
|
||||
'429': {$ref: '#/components/responses/RateLimited'}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
/growth-coach/plans:
|
||||
get:
|
||||
tags: [Growth coach]
|
||||
operationId: listGrowthCoachPlans
|
||||
parameters:
|
||||
- {name: terminalId, in: query, required: false, schema: {type: string, maxLength: 128}}
|
||||
responses:
|
||||
'200': {description: Coach plans., content: {application/json: {schema: {type: object, required: [plans], properties: {plans: {type: array, items: {$ref: '#/components/schemas/GrowthCoachPlan'}}}}}}}
|
||||
/growth-coach/actions:
|
||||
get:
|
||||
tags: [Growth coach]
|
||||
operationId: listGoldenSteps
|
||||
parameters:
|
||||
- {name: terminalId, in: query, required: false, schema: {type: string, maxLength: 128}}
|
||||
responses:
|
||||
'200': {description: Shared Golden Steps workspace., content: {application/json: {schema: {type: object, required: [actions], properties: {actions: {type: array, items: {$ref: '#/components/schemas/GoldenStep'}}}}}}}
|
||||
/growth-coach/goals:
|
||||
get:
|
||||
tags: [Growth coach]
|
||||
operationId: listMonthlyGoals
|
||||
parameters:
|
||||
- {name: terminalId, in: query, required: false, schema: {type: string, maxLength: 128}}
|
||||
responses:
|
||||
'200': {description: Automatically tracked monthly goals with manual action subtasks., content: {application/json: {schema: {type: object, required: [goals], properties: {goals: {type: array, items: {$ref: '#/components/schemas/MonthlyGoal'}}}}}}}
|
||||
/growth-coach/goals/{goalId}/subtasks/{subtaskId}/transitions:
|
||||
post:
|
||||
tags: [Growth coach]
|
||||
operationId: transitionGoalSubtask
|
||||
parameters:
|
||||
- {name: goalId, in: path, required: true, schema: {type: string}}
|
||||
- {name: subtaskId, in: path, required: true, schema: {type: string}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [transition], properties: {transition: {type: string, enum: [COMPLETE, REOPEN]}}}}}}
|
||||
responses:
|
||||
'200': {description: Updated user-completed subtask., content: {application/json: {schema: {$ref: '#/components/schemas/GoalSubtask'}}}}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/growth-coach/deadline-proposals/{proposalId}/decisions:
|
||||
post:
|
||||
tags: [Growth coach]
|
||||
operationId: decideGoalDeadlineProposal
|
||||
parameters:
|
||||
- {name: proposalId, in: path, required: true, schema: {type: string}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [decision], properties: {decision: {type: string, enum: [ACCEPT, REJECT]}}}}}}
|
||||
responses:
|
||||
'200': {description: Deadline proposal decision., content: {application/json: {schema: {$ref: '#/components/schemas/GoalDeadlineProposal'}}}}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/growth-coach/recommendations/{id}/decisions:
|
||||
post:
|
||||
tags: [Growth coach]
|
||||
operationId: decideGrowthCoachRecommendation
|
||||
parameters:
|
||||
- {name: id, in: path, required: true, schema: {type: string}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/CoachDecision'}}}}
|
||||
responses:
|
||||
'200': {description: Decision recorded and accepted action created when applicable.}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/growth-coach/actions/{id}/transitions:
|
||||
post:
|
||||
tags: [Growth coach]
|
||||
operationId: transitionGoldenStep
|
||||
parameters:
|
||||
- {name: id, in: path, required: true, schema: {type: string}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
requestBody: {required: true, content: {application/json: {schema: {type: object, additionalProperties: false, required: [transition], properties: {transition: {type: string, enum: [START, COMPLETE, ABANDON]}}}}}}
|
||||
responses:
|
||||
'200': {description: Updated action., content: {application/json: {schema: {$ref: '#/components/schemas/GoldenStep'}}}}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/growth-coach/difficulty-proposals/{id}/decisions:
|
||||
post:
|
||||
tags: [Growth coach]
|
||||
operationId: decideGrowthCoachDifficulty
|
||||
parameters:
|
||||
- {name: id, in: path, required: true, schema: {type: string}}
|
||||
- $ref: '#/components/parameters/IdempotencyKeyHeader'
|
||||
- $ref: '#/components/parameters/CsrfTokenHeader'
|
||||
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/CoachDecision'}}}}
|
||||
responses:
|
||||
'200': {description: Difficulty decision recorded.}
|
||||
'409': {$ref: '#/components/responses/Conflict'}
|
||||
/growth-coach/refreshes/{jobId}:
|
||||
get:
|
||||
tags: [Growth coach]
|
||||
operationId: getGrowthCoachJob
|
||||
parameters: [{name: jobId, in: path, required: true, schema: {type: string}}]
|
||||
responses:
|
||||
'200': {description: Generation job., content: {application/json: {schema: {$ref: '#/components/schemas/GrowthCoachJob'}}}}
|
||||
'404': {$ref: '#/components/responses/ResourceNotFound'}
|
||||
/growth-coach/refreshes/{jobId}/events:
|
||||
get:
|
||||
tags: [Growth coach]
|
||||
operationId: streamGrowthCoachJob
|
||||
parameters: [{name: jobId, in: path, required: true, schema: {type: string}}]
|
||||
responses:
|
||||
'200': {description: Job snapshots., content: {text/event-stream: {schema: {type: string}}}}
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
merchantSession:
|
||||
@@ -1064,6 +1243,208 @@ components:
|
||||
$ref: '#/components/schemas/Problem'
|
||||
|
||||
schemas:
|
||||
GrowthCoachProfileInput:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [businessDescription, niches, salesChannels, primaryGoal, constraints]
|
||||
properties:
|
||||
businessDescription: {type: string, minLength: 20, maxLength: 2000}
|
||||
niches: {type: array, minItems: 1, maxItems: 10, items: {type: string, maxLength: 80}}
|
||||
salesChannels: {type: array, minItems: 1, maxItems: 10, items: {type: string, maxLength: 80}}
|
||||
primaryGoal: {type: string, minLength: 3, maxLength: 500}
|
||||
constraints: {type: string, maxLength: 1000}
|
||||
GrowthCoachProfile:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/GrowthCoachProfileInput'
|
||||
- type: object
|
||||
required: [profileId, terminalId, version, difficulty, createdAt]
|
||||
properties:
|
||||
profileId: {type: string}
|
||||
terminalId: {type: string}
|
||||
version: {type: integer, minimum: 1}
|
||||
difficulty: {type: integer, minimum: 1, maximum: 5}
|
||||
createdAt: {type: string, format: date-time}
|
||||
GrowthCoachJob:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [jobId, state, eventsUrl, createdAt, updatedAt]
|
||||
properties:
|
||||
jobId: {type: string}
|
||||
state: {type: string, enum: [QUEUED, RUNNING, COMPLETED, FAILED]}
|
||||
eventsUrl: {type: string}
|
||||
createdAt: {type: string, format: date-time}
|
||||
updatedAt: {type: string, format: date-time}
|
||||
GrowthCoachRefreshInput:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [cadence]
|
||||
properties:
|
||||
cadence: {type: string, enum: [WEEKLY, MONTHLY]}
|
||||
GrowthCoachProfileResult:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [profile, generationJobs, pageInsightJobs]
|
||||
properties:
|
||||
profile: {$ref: '#/components/schemas/GrowthCoachProfile'}
|
||||
generationJobs: {type: array, items: {$ref: '#/components/schemas/GrowthCoachJob'}}
|
||||
pageInsightJobs: {type: array, items: {$ref: '#/components/schemas/AIInsightJob'}}
|
||||
GrowthCoachRecommendation:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [recommendationId, planId, rank, status, actionType, title, rationale, expectedImpact, effort, evidenceIds, sampleSize, deadline, subtasks, eventIds]
|
||||
properties:
|
||||
recommendationId: {type: string}
|
||||
planId: {type: string}
|
||||
rank: {type: integer, minimum: 1, maximum: 3}
|
||||
status: {type: string, enum: [OFFERED, ACCEPTED, REJECTED, EXPIRED]}
|
||||
actionType: {type: string, enum: [MANUAL, METRIC]}
|
||||
title: {type: string}
|
||||
rationale: {type: string}
|
||||
expectedImpact: {type: string}
|
||||
effort: {type: string, enum: [LOW, MEDIUM, HIGH]}
|
||||
evidenceIds: {type: array, items: {type: string}}
|
||||
metricId: {type: [string, 'null']}
|
||||
metricDirection: {type: [string, 'null']}
|
||||
actionLevel: {type: [string, 'null']}
|
||||
baseline: {type: [number, 'null']}
|
||||
target: {type: [number, 'null']}
|
||||
sampleSize: {type: integer, format: int64}
|
||||
deadline: {type: string, format: date}
|
||||
subtasks: {type: array, minItems: 3, maxItems: 7, items: {$ref: '#/components/schemas/GeneratedGoalSubtask'}}
|
||||
eventIds: {type: array, items: {type: string}}
|
||||
GeneratedGoalSubtask:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [title, deadline, eventId]
|
||||
properties:
|
||||
title: {type: string}
|
||||
deadline: {type: [string, 'null'], format: date}
|
||||
eventId: {type: [string, 'null']}
|
||||
GoalSubtask:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [subtaskId, position, title, status, deadline]
|
||||
properties:
|
||||
subtaskId: {type: string}
|
||||
position: {type: integer, minimum: 1, maximum: 7}
|
||||
title: {type: string}
|
||||
status: {type: string, enum: [TODO, DONE]}
|
||||
deadline: {type: string, format: date}
|
||||
eventId: {type: [string, 'null']}
|
||||
completedAt: {type: [string, 'null'], format: date-time}
|
||||
GoalDeadlineProposal:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [proposalId, goalId, subtaskId, eventId, currentDeadline, proposedDeadline, reason, status]
|
||||
properties:
|
||||
proposalId: {type: string}
|
||||
goalId: {type: string}
|
||||
subtaskId: {type: string}
|
||||
eventId: {type: string}
|
||||
currentDeadline: {type: string, format: date}
|
||||
proposedDeadline: {type: string, format: date}
|
||||
reason: {type: string}
|
||||
status: {type: string, enum: [OFFERED, ACCEPTED, REJECTED, EXPIRED]}
|
||||
decidedAt: {type: [string, 'null'], format: date-time}
|
||||
MonthlyGoal:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [goalId, recommendationId, terminalId, title, expectedImpact, status, metricId, metricDirection, baseline, target, currentValue, progressPercent, sampleSize, deadline, eventIds, subtasks, deadlineProposals, updatedAt]
|
||||
properties:
|
||||
goalId: {type: string}
|
||||
recommendationId: {type: string}
|
||||
terminalId: {type: string}
|
||||
title: {type: string}
|
||||
expectedImpact: {type: string}
|
||||
status: {type: string, enum: [ACTIVE, COMPLETED, MISSED, ABANDONED]}
|
||||
metricId: {type: string, enum: [paid_count, paid_amount, fee_amount, avg_latency, success_rate]}
|
||||
metricDirection: {type: string, enum: [INCREASE, DECREASE]}
|
||||
baseline: {type: number}
|
||||
target: {type: number}
|
||||
currentValue: {type: number}
|
||||
progressPercent: {type: number, minimum: 0, maximum: 100}
|
||||
sampleSize: {type: integer, format: int64}
|
||||
deadline: {type: string, format: date}
|
||||
eventIds: {type: array, items: {type: string}}
|
||||
subtasks: {type: array, items: {$ref: '#/components/schemas/GoalSubtask'}}
|
||||
deadlineProposals: {type: array, items: {$ref: '#/components/schemas/GoalDeadlineProposal'}}
|
||||
updatedAt: {type: string, format: date-time}
|
||||
GrowthCoachPlan:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [planId, cadence, status, periodStart, periodEnd, difficulty, suggestions, generatedAt]
|
||||
properties:
|
||||
planId: {type: string}
|
||||
parentId: {type: [string, 'null']}
|
||||
cadence: {type: string, enum: [DAILY, WEEKLY, MONTHLY]}
|
||||
status: {type: string}
|
||||
periodStart: {type: string, format: date}
|
||||
periodEnd: {type: string, format: date}
|
||||
dailyBrief: {type: [string, 'null']}
|
||||
difficulty: {type: integer, minimum: 1, maximum: 5}
|
||||
suggestions: {type: array, items: {$ref: '#/components/schemas/GrowthCoachRecommendation'}}
|
||||
generatedAt: {type: string, format: date-time}
|
||||
GoldenStep:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [actionId, recommendationId, terminalId, actionType, title, status, sampleSize, deadline, updatedAt]
|
||||
properties:
|
||||
actionId: {type: string}
|
||||
recommendationId: {type: string}
|
||||
terminalId: {type: string}
|
||||
actionType: {type: string, enum: [MANUAL, METRIC]}
|
||||
title: {type: string}
|
||||
status: {type: string, enum: [NOT_STARTED, IN_PROGRESS, COMPLETED, ABANDONED, MISSED]}
|
||||
metricId: {type: [string, 'null']}
|
||||
metricDirection: {type: [string, 'null']}
|
||||
baseline: {type: [number, 'null']}
|
||||
target: {type: [number, 'null']}
|
||||
currentValue: {type: [number, 'null']}
|
||||
sampleSize: {type: integer, format: int64}
|
||||
deadline: {type: string, format: date}
|
||||
updatedAt: {type: string, format: date-time}
|
||||
GrowthCoachTerminalRollup:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [terminalId, onboardingStatus, activeActions, overdueActions, completionRate]
|
||||
properties:
|
||||
terminalId: {type: string}
|
||||
onboardingStatus: {type: string, enum: [REQUIRED, COMPLETE]}
|
||||
activeActions: {type: integer}
|
||||
overdueActions: {type: integer}
|
||||
completionRate: {type: number, minimum: 0, maximum: 1}
|
||||
GrowthCoachDashboard:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [scope, generationState, plans, actions, terminals, difficultyProposals]
|
||||
properties:
|
||||
scope: {type: string, enum: [TERMINAL, ALL_TERMINALS]}
|
||||
terminalId: {type: [string, 'null']}
|
||||
dataThrough: {type: [string, 'null'], format: date}
|
||||
generationState: {type: string, enum: [ONBOARDING_REQUIRED, GENERATING, IDLE, UNAVAILABLE]}
|
||||
profile: {anyOf: [{$ref: '#/components/schemas/GrowthCoachProfile'}, {type: 'null'}]}
|
||||
plans: {type: array, items: {$ref: '#/components/schemas/GrowthCoachPlan'}}
|
||||
actions: {type: array, items: {$ref: '#/components/schemas/GoldenStep'}}
|
||||
terminals: {type: array, items: {$ref: '#/components/schemas/GrowthCoachTerminalRollup'}}
|
||||
difficultyProposals: {type: array, items: {$ref: '#/components/schemas/GrowthCoachDifficultyProposal'}}
|
||||
GrowthCoachDifficultyProposal:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [proposalId, fromLevel, toLevel, reason, status]
|
||||
properties:
|
||||
proposalId: {type: string}
|
||||
fromLevel: {type: integer, minimum: 1, maximum: 5}
|
||||
toLevel: {type: integer, minimum: 1, maximum: 5}
|
||||
reason: {type: string}
|
||||
status: {type: string, enum: [OFFERED, ACCEPTED, REJECTED, EXPIRED]}
|
||||
CoachDecision:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [decision, reason, note]
|
||||
properties:
|
||||
decision: {type: string, enum: [ACCEPTED, REJECTED]}
|
||||
reason: {type: string, maxLength: 100}
|
||||
note: {type: string, maxLength: 500}
|
||||
CreateGrowthReportRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1147,6 +1528,26 @@ components:
|
||||
expectedSessions: {$ref: '#/components/schemas/GrowthRange'}
|
||||
expectedAmountRial: {$ref: '#/components/schemas/GrowthRange'}
|
||||
historicalEvidenceId: {type: string}
|
||||
GrowthUpcomingEvent:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [evidenceId, eventId, eventTitleFa, date, eventType, officialHoliday, merchantCategories, behavioralChannels]
|
||||
properties:
|
||||
evidenceId: {type: string}
|
||||
eventId: {type: string}
|
||||
eventTitleFa: {type: string}
|
||||
date: {type: string, format: date-time}
|
||||
eventType: {type: string}
|
||||
officialHoliday: {type: boolean}
|
||||
merchantCategories: {type: array, items: {type: string}}
|
||||
behavioralChannels: {type: array, items: {type: string}}
|
||||
GrowthEventRecommendation:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [evidenceId, relevanceReason]
|
||||
properties:
|
||||
evidenceId: {type: string}
|
||||
relevanceReason: {type: string, minLength: 1, maxLength: 320}
|
||||
GrowthRisk:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1197,14 +1598,17 @@ components:
|
||||
GrowthEvidence:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [forecast, historicalWins, opportunities, risks, fallbackBriefs]
|
||||
required: [events, merchantContext]
|
||||
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/GrowthFallbackBrief'}}
|
||||
events: {type: array, maxItems: 5, items: {$ref: '#/components/schemas/GrowthUpcomingEvent'}}
|
||||
merchantContext:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [category, niches, salesChannels]
|
||||
properties:
|
||||
category: {type: string}
|
||||
niches: {type: array, items: {type: string}}
|
||||
salesChannels: {type: array, items: {type: string}}
|
||||
GrowthReport:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1218,13 +1622,13 @@ components:
|
||||
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'}}}
|
||||
required: [eventRecommendations]
|
||||
properties:
|
||||
eventRecommendations: {type: array, minItems: 3, maxItems: 3, items: {$ref: '#/components/schemas/GrowthEventRecommendation'}}
|
||||
failureCode: {type: string}
|
||||
cached: {type: boolean}
|
||||
stale: {type: boolean}
|
||||
@@ -1279,13 +1683,13 @@ components:
|
||||
AIInsight:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [insightId, module, revision, status, scope, asOfDate, dataThroughDate, forecastStartDate, freshness, dataLagDays, confidence, copy, evidence, calendarContext, refreshState, generatedAt]
|
||||
required: [insightId, module, revision, status, scope, asOfDate, dataThroughDate, forecastStartDate, freshness, dataLagDays, confidence, copy, evidence, calendarContext, refreshState, sectionRefreshState, generatedAt]
|
||||
properties:
|
||||
insightId: {type: string}
|
||||
module: {$ref: '#/components/schemas/AIInsightModule'}
|
||||
revision: {type: integer, minimum: 1}
|
||||
status: {type: string, enum: [READY, PARTIAL]}
|
||||
scope: {type: object, properties: {terminalId: {type: [string, 'null']}}}
|
||||
scope: {type: object, properties: {terminalId: {type: [string, 'null']}, periodId: {type: [string, 'null']}}}
|
||||
asOfDate: {type: string, format: date}
|
||||
dataThroughDate: {type: string, format: date}
|
||||
forecastStartDate: {type: string, format: date}
|
||||
@@ -1296,22 +1700,41 @@ components:
|
||||
evidence: {type: object, additionalProperties: true}
|
||||
calendarContext: {type: array, items: {type: object, additionalProperties: true}}
|
||||
refreshState: {type: object, additionalProperties: true}
|
||||
sectionRefreshState:
|
||||
type: object
|
||||
additionalProperties: {$ref: '#/components/schemas/AIInsightRefreshState'}
|
||||
generatedAt: {type: string, format: date-time}
|
||||
AIInsightRefreshRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
properties: {terminalId: {type: string, maxLength: 128}}
|
||||
properties:
|
||||
terminalId: {type: string, maxLength: 128}
|
||||
periodId: {type: string, maxLength: 128, description: Used only by the transactions module.}
|
||||
AIInsightJob:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [jobId, snapshotId, state, eventsUrl, createdAt, updatedAt]
|
||||
required: [jobId, snapshotId, module, sectionId, state, eventsUrl, createdAt, updatedAt]
|
||||
properties:
|
||||
jobId: {type: string}
|
||||
snapshotId: {type: string}
|
||||
module: {$ref: '#/components/schemas/AIInsightModule'}
|
||||
sectionId: {type: string, enum: [full, past, latest-observed, future-7-days, future-30-days, future-90-days, findings, options]}
|
||||
state: {type: string, enum: [QUEUED, RUNNING, COMPLETED, FAILED]}
|
||||
eventsUrl: {type: string, format: uri-reference}
|
||||
createdAt: {type: string, format: date-time}
|
||||
updatedAt: {type: string, format: date-time}
|
||||
AIInsightSection:
|
||||
type: string
|
||||
enum: [past, latest-observed, future-7-days, future-30-days, future-90-days, findings, options]
|
||||
AIInsightRefreshState:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [state]
|
||||
properties:
|
||||
state: {type: string, enum: [IDLE, QUEUED, RUNNING, FAILED, LIMITED]}
|
||||
jobId: {type: string}
|
||||
eventsUrl: {type: string, format: uri-reference}
|
||||
nextRefreshAt: {type: string, format: date-time}
|
||||
LoginRequest:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1529,7 +1952,7 @@ components:
|
||||
|
||||
SectionId:
|
||||
type: string
|
||||
enum: [overview, payment_performance, fees, peer_comparison]
|
||||
enum: [overview, payment_performance, fees, peer_comparison, transactions]
|
||||
|
||||
AnalyticsRunState:
|
||||
type: string
|
||||
@@ -1566,7 +1989,7 @@ components:
|
||||
description: Opaque identifier for the immutable completed-import snapshot.
|
||||
metricDefinitionVersion:
|
||||
type: string
|
||||
const: 0.4.0
|
||||
const: 0.5.0
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
@@ -1581,7 +2004,7 @@ components:
|
||||
sections:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [overview, paymentPerformance, fees, peerComparison]
|
||||
required: [overview, paymentPerformance, fees, peerComparison, transactions]
|
||||
properties:
|
||||
overview:
|
||||
$ref: '#/components/schemas/OverviewSection'
|
||||
@@ -1591,6 +2014,8 @@ components:
|
||||
$ref: '#/components/schemas/FeesSection'
|
||||
peerComparison:
|
||||
$ref: '#/components/schemas/PeerComparisonSection'
|
||||
transactions:
|
||||
$ref: '#/components/schemas/TransactionsSection'
|
||||
|
||||
QueuedSection:
|
||||
type: object
|
||||
@@ -1649,7 +2074,7 @@ components:
|
||||
pattern: '^ds_[A-Za-z0-9_-]{8,60}$'
|
||||
metricDefinitionVersion:
|
||||
type: string
|
||||
const: 0.4.0
|
||||
const: 0.5.0
|
||||
|
||||
IntegerMetric:
|
||||
type: object
|
||||
@@ -1823,6 +2248,58 @@ components:
|
||||
initTiming: {$ref: '#/components/schemas/TimingDistribution'}
|
||||
verifyTiming: {$ref: '#/components/schemas/TimingDistribution'}
|
||||
|
||||
TransactionStatusDistribution:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [status, count, sharePercent]
|
||||
properties:
|
||||
status: {$ref: '#/components/schemas/SessionStatus'}
|
||||
count:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
sharePercent:
|
||||
type: [string, 'null']
|
||||
pattern: '^(100|[0-9]{1,2})(\.[0-9]{1,6})?$'
|
||||
|
||||
TransactionStatusTrendPoint:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [localDate, paidSessions, verifiedSessions, failedSessions, reversedSessions, totalSessions]
|
||||
properties:
|
||||
localDate:
|
||||
type: string
|
||||
format: date
|
||||
localHour:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 23
|
||||
paidSessions: {type: integer, format: int64, minimum: 0}
|
||||
verifiedSessions: {type: integer, format: int64, minimum: 0}
|
||||
failedSessions: {type: integer, format: int64, minimum: 0}
|
||||
reversedSessions: {type: integer, format: int64, minimum: 0}
|
||||
totalSessions: {type: integer, format: int64, minimum: 0}
|
||||
|
||||
TransactionsData:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [totalSessions, bankSuccessRate, verificationCompletionRate, failureRate, statusDistribution, statusTrend]
|
||||
properties:
|
||||
totalSessions: {$ref: '#/components/schemas/IntegerMetric'}
|
||||
bankSuccessRate: {$ref: '#/components/schemas/DecimalMetric'}
|
||||
verificationCompletionRate: {$ref: '#/components/schemas/DecimalMetric'}
|
||||
failureRate: {$ref: '#/components/schemas/DecimalMetric'}
|
||||
statusDistribution:
|
||||
type: array
|
||||
minItems: 4
|
||||
maxItems: 4
|
||||
description: Canonical order is Paid, Verified, Failed, Reversed.
|
||||
items: {$ref: '#/components/schemas/TransactionStatusDistribution'}
|
||||
statusTrend:
|
||||
type: array
|
||||
maxItems: 31
|
||||
items: {$ref: '#/components/schemas/TransactionStatusTrendPoint'}
|
||||
|
||||
FeesData:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1898,6 +2375,16 @@ components:
|
||||
metadata: {$ref: '#/components/schemas/ReadySectionMetadata'}
|
||||
data: {$ref: '#/components/schemas/PaymentPerformanceData'}
|
||||
|
||||
TransactionsReadySection:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
required: [sectionId, state, metadata, data]
|
||||
properties:
|
||||
sectionId: {type: string, const: transactions}
|
||||
state: {type: string, const: READY}
|
||||
metadata: {$ref: '#/components/schemas/ReadySectionMetadata'}
|
||||
data: {$ref: '#/components/schemas/TransactionsData'}
|
||||
|
||||
FeesReadySection:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
@@ -1966,6 +2453,12 @@ components:
|
||||
- $ref: '#/components/schemas/CalculatingSection'
|
||||
- $ref: '#/components/schemas/FailedSection'
|
||||
- $ref: '#/components/schemas/PaymentPerformanceReadySection'
|
||||
TransactionsSection:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/QueuedSection'
|
||||
- $ref: '#/components/schemas/CalculatingSection'
|
||||
- $ref: '#/components/schemas/FailedSection'
|
||||
- $ref: '#/components/schemas/TransactionsReadySection'
|
||||
FeesSection:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/QueuedSection'
|
||||
@@ -2172,6 +2665,7 @@ components:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/OverviewReadySection'
|
||||
- $ref: '#/components/schemas/PaymentPerformanceReadySection'
|
||||
- $ref: '#/components/schemas/TransactionsReadySection'
|
||||
- $ref: '#/components/schemas/FeesReadySection'
|
||||
- $ref: '#/components/schemas/PeerComparisonReadySection'
|
||||
SectionFailedEvent:
|
||||
|
||||
Reference in New Issue
Block a user