|
|
|
|
@@ -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:
|
|
|
|
|
|