This commit is contained in:
2026-03-17 18:32:44 +03:00
commit efcd4a8dfd
209 changed files with 33355 additions and 0 deletions
+556
View File
@@ -0,0 +1,556 @@
openapi: 3.0.3
info:
title: Travel Product Manager API
version: 1.0.0
description: |
Synthetic API for a single travel offer workflow.
Intended order of operations:
1. get recent users,
2. get top hotels,
3. build hotel preference segments from users and hotels,
4. build user-to-hotel assignments from segments,
5. send hotel offers by email from assignments.
Each endpoint has one specific responsibility.
The workflow should be interpreted as a strict data pipeline where the output
array of one step becomes the input field of the next step.
servers:
- url: http://demo-api:8010
- url: http://localhost:8010
- url: https://api.travel.example.com
paths:
/users/recent:
get:
operationId: getRecentUsers
tags:
- travel-offer-workflow
summary: Get recent users for travel campaigns
description: |
Returns a list of recent users active in the last 7 days.
By default this endpoint returns up to 30 users because the limit parameter
defaults to 30.
Output of this endpoint is the users array that should be passed as the users
field to /segments/hotel.
This endpoint does not retrieve hotels, create segments, create assignments,
or send emails.
parameters:
- in: query
name: last_active_after
schema:
type: string
format: date-time
required: false
description: |
Optional lower bound for user activity time.
Only users active after this timestamp should be returned.
If omitted, the endpoint behaves like "last 7 days".
- in: query
name: limit
schema:
type: integer
minimum: 1
maximum: 100
default: 30
required: false
description: |
Maximum number of users to return.
If omitted, the endpoint returns up to 30 users.
responses:
"200":
description: |
Successful response containing the users array for the first workflow step.
This users array should be passed forward to /segments/hotel.
content:
application/json:
schema:
$ref: "#/components/schemas/RecentUsersResponse"
examples:
sample:
value:
users:
- id: usr_001
email: user001@example.com
last_active: "2026-03-13T10:00:00Z"
- id: usr_002
email: user002@example.com
last_active: "2026-03-13T09:55:00Z"
- id: usr_003
email: user003@example.com
last_active: "2026-03-13T09:50:00Z"
- id: usr_004
email: user004@example.com
last_active: "2026-03-13T09:45:00Z"
- id: usr_005
email: user005@example.com
last_active: "2026-03-13T09:40:00Z"
- id: usr_006
email: user006@example.com
last_active: "2026-03-13T09:35:00Z"
- id: usr_007
email: user007@example.com
last_active: "2026-03-13T09:30:00Z"
- id: usr_008
email: user008@example.com
last_active: "2026-03-13T09:25:00Z"
- id: usr_009
email: user009@example.com
last_active: "2026-03-13T09:20:00Z"
- id: usr_010
email: user010@example.com
last_active: "2026-03-13T09:15:00Z"
- id: usr_011
email: user011@example.com
last_active: "2026-03-13T09:10:00Z"
- id: usr_012
email: user012@example.com
last_active: "2026-03-13T09:05:00Z"
- id: usr_013
email: user013@example.com
last_active: "2026-03-13T09:00:00Z"
- id: usr_014
email: user014@example.com
last_active: "2026-03-13T08:55:00Z"
- id: usr_015
email: user015@example.com
last_active: "2026-03-13T08:50:00Z"
- id: usr_016
email: user016@example.com
last_active: "2026-03-13T08:45:00Z"
- id: usr_017
email: user017@example.com
last_active: "2026-03-13T08:40:00Z"
- id: usr_018
email: user018@example.com
last_active: "2026-03-13T08:35:00Z"
- id: usr_019
email: user019@example.com
last_active: "2026-03-13T08:30:00Z"
- id: usr_020
email: user020@example.com
last_active: "2026-03-13T08:25:00Z"
- id: usr_021
email: user021@example.com
last_active: "2026-03-13T08:20:00Z"
- id: usr_022
email: user022@example.com
last_active: "2026-03-13T08:15:00Z"
- id: usr_023
email: user023@example.com
last_active: "2026-03-13T08:10:00Z"
- id: usr_024
email: user024@example.com
last_active: "2026-03-13T08:05:00Z"
- id: usr_025
email: user025@example.com
last_active: "2026-03-13T08:00:00Z"
- id: usr_026
email: user026@example.com
last_active: "2026-03-13T07:55:00Z"
- id: usr_027
email: user027@example.com
last_active: "2026-03-13T07:50:00Z"
- id: usr_028
email: user028@example.com
last_active: "2026-03-13T07:45:00Z"
- id: usr_029
email: user029@example.com
last_active: "2026-03-13T07:40:00Z"
- id: usr_030
email: user030@example.com
last_active: "2026-03-13T07:35:00Z"
/hotels/top:
get:
operationId: getTopHotels
tags:
- travel-offer-workflow
summary: Get top hotels for offers
description: |
Returns a list of candidate hotels for the offer workflow.
By default this endpoint returns up to 5 hotels because the limit parameter
defaults to 5.
Output of this endpoint is the hotels array that should be passed as the hotels
field to /segments/hotel.
This endpoint does not retrieve users, create segments, create assignments,
or send emails.
parameters:
- in: query
name: limit
schema:
type: integer
minimum: 1
maximum: 20
default: 5
required: false
description: |
Maximum number of hotels to return.
If omitted, the endpoint returns up to 5 hotels.
- in: query
name: city
schema:
type: string
required: false
description: |
Optional city filter.
If provided, only hotels from this city should be returned.
responses:
"200":
description: |
Successful response containing the hotels array for the second workflow step.
This hotels array should be passed forward to /segments/hotel.
content:
application/json:
schema:
$ref: "#/components/schemas/TopHotelsResponse"
examples:
sample:
value:
hotels:
- id: hotel_001
name: Hotel Aurora
city: Berlin
- id: hotel_002
name: Sea Breeze Resort
city: Lisbon
- id: hotel_003
name: Mountain Vista
city: Zurich
- id: hotel_004
name: City Loft
city: Amsterdam
- id: hotel_005
name: River Palace
city: Prague
/segments/hotel:
post:
operationId: segmentUsersByHotelPreferences
tags:
- travel-offer-workflow
summary: Segment recent users by hotel preferences
description: |
Creates hotel-based user segments from two required inputs in one request:
users and hotels.
The users field must contain the users array returned by /users/recent.
The hotels field must contain the hotels array returned by /hotels/top.
A common workflow is: get up to 30 recent users, get top hotels, then send
both arrays to this endpoint to distribute users across hotels by preference.
Output of this endpoint is the segments array used as the segments field in
/assignments/hotels.
This endpoint does not send emails.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/HotelSegmentsRequest"
examples:
sample:
value:
users:
- id: usr_001
email: user001@example.com
last_active: "2026-03-13T10:00:00Z"
hotels:
- id: hotel_001
name: Hotel Aurora
city: Berlin
responses:
"200":
description: |
Successful response containing the segments array.
This segments array should be passed forward to /assignments/hotels.
content:
application/json:
schema:
$ref: "#/components/schemas/HotelSegmentsResponse"
examples:
sample:
value:
segments:
- segment_id: seg_berlin
hotel_id: hotel_001
user_ids: ["usr_001", "usr_002"]
/assignments/hotels:
post:
operationId: assignUsersToHotels
tags:
- travel-offer-workflow
summary: Assign users to hotels based on segments
description: |
Builds final user-to-hotel assignments from segments.
The segments field must contain the segments array returned by /segments/hotel.
Output of this endpoint is the assignments array used as the assignments field
in /emails/send-offers.
This endpoint does not send emails and does not fetch users or hotels.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/AssignmentsRequest"
examples:
sample:
value:
segments:
- segment_id: seg_berlin
hotel_id: hotel_001
user_ids: ["usr_001", "usr_002"]
responses:
"200":
description: |
Successful response containing the assignments array.
This assignments array should be passed forward to /emails/send-offers.
content:
application/json:
schema:
$ref: "#/components/schemas/AssignmentsResponse"
examples:
sample:
value:
assignments:
- user_id: usr_001
hotel_id: hotel_001
- user_id: usr_002
hotel_id: hotel_001
/emails/send-offers:
post:
operationId: sendHotelOffersByEmail
tags:
- travel-offer-workflow
summary: Send hotel offers by email
description: |
Sends hotel offer emails to users based on final assignments.
The assignments field must contain the assignments array returned by
/assignments/hotels.
This endpoint is the final delivery step of the workflow.
It does not build new segments or assignments.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/EmailOfferRequest"
examples:
sample:
value:
template_id: offer_template_2026
assignments:
- user_id: usr_001
hotel_id: hotel_001
- user_id: usr_002
hotel_id: hotel_001
responses:
"200":
description: |
Successful response containing the result of the email delivery step.
This is the final output of the workflow.
content:
application/json:
schema:
$ref: "#/components/schemas/EmailOfferResponse"
examples:
sample:
value:
sent_count: 2
failed_count: 0
failed: []
components:
schemas:
User:
description: |
A recent user eligible to receive a hotel offer email.
User objects are produced by /users/recent and then reused in
/segments/hotel.
type: object
required: [id, email, last_active]
properties:
id:
type: string
description: Stable unique user identifier.
email:
type: string
format: email
description: Email address used in the final offer delivery step.
last_active:
type: string
format: date-time
description: Most recent activity timestamp used to identify recent users.
Hotel:
description: |
A hotel candidate that may be recommended to users.
Hotel objects are produced by /hotels/top and then reused in
/segments/hotel.
type: object
required: [id, name, city]
properties:
id:
type: string
description: Stable unique hotel identifier.
name:
type: string
description: Human-readable hotel name shown in offers.
city:
type: string
description: City where the hotel is located.
Segment:
description: |
A hotel preference segment that groups users for one hotel.
Segment objects are produced by /segments/hotel and then reused in
/assignments/hotels.
type: object
required: [segment_id, hotel_id, user_ids]
properties:
segment_id:
type: string
description: Stable unique segment identifier.
hotel_id:
type: string
description: Hotel identifier associated with this segment.
user_ids:
type: array
description: User identifiers that belong to this hotel preference segment.
items:
type: string
Assignment:
description: |
A final mapping between one user and one hotel offer.
Assignment objects are produced by /assignments/hotels and then reused in
/emails/send-offers.
type: object
required: [user_id, hotel_id]
properties:
user_id:
type: string
description: Identifier of the user who should receive the offer.
hotel_id:
type: string
description: Identifier of the hotel assigned to the user.
RecentUsersResponse:
description: Response containing the users array produced by /users/recent.
type: object
required: [users]
properties:
users:
type: array
description: |
Recent users that should be copied into the users field of
/segments/hotel. With the default limit this array usually contains
up to 30 users.
items:
$ref: "#/components/schemas/User"
TopHotelsResponse:
description: Response containing the hotels array produced by /hotels/top.
type: object
required: [hotels]
properties:
hotels:
type: array
description: |
Candidate hotels that should be copied into the hotels field of
/segments/hotel. With the default limit this array usually contains
up to 5 hotels.
items:
$ref: "#/components/schemas/Hotel"
HotelSegmentsRequest:
description: |
Request body for building segments from users and hotels.
This request combines the users array from /users/recent and the hotels array
from /hotels/top.
type: object
required: [users, hotels]
properties:
users:
type: array
description: |
Users from /users/recent. This is typically the same array of up to 30
recent users returned by the first step. These users are being
distributed across candidate hotels by preference.
items:
$ref: "#/components/schemas/User"
hotels:
type: array
description: |
Hotels from /hotels/top that should be used as candidate destinations
for user distribution.
items:
$ref: "#/components/schemas/Hotel"
HotelSegmentsResponse:
description: Response containing the segments array produced by /segments/hotel.
type: object
required: [segments]
properties:
segments:
type: array
description: |
Segments that should be copied into the segments field of
/assignments/hotels.
items:
$ref: "#/components/schemas/Segment"
AssignmentsRequest:
description: |
Request body for building assignments from the segments array returned by
/segments/hotel.
type: object
required: [segments]
properties:
segments:
type: array
description: |
Segments from /segments/hotel that should be converted into final
user-to-hotel assignments.
items:
$ref: "#/components/schemas/Segment"
AssignmentsResponse:
description: Response containing the assignments array produced by /assignments/hotels.
type: object
required: [assignments]
properties:
assignments:
type: array
description: |
Assignments that should be copied into the assignments field of
/emails/send-offers.
items:
$ref: "#/components/schemas/Assignment"
EmailOfferRequest:
description: |
Request body for sending offer emails from the assignments array returned
by /assignments/hotels.
type: object
required: [template_id, assignments]
properties:
template_id:
type: string
default: offer_template_2026
description: Identifier of the email template to use for every assignment in this request.
assignments:
type: array
description: |
Assignments from /assignments/hotels that should be emailed in the
final step.
items:
$ref: "#/components/schemas/Assignment"
EmailOfferResponse:
description: |
Result of the final email delivery step.
This response does not contain new users, hotels, segments, or assignments.
type: object
required: [sent_count, failed_count, failed]
properties:
sent_count:
type: integer
description: Number of assignments for which an email was sent successfully.
failed_count:
type: integer
description: Number of assignments for which email delivery failed.
failed:
type: array
description: Failed deliveries with reasons for each affected user.
items:
type: object
required: [user_id, reason]
properties:
user_id:
type: string
description: Identifier of the user whose email delivery failed.
reason:
type: string
description: Human-readable explanation of why the email could not be sent.