From ad980a83aa376a1ac6e1a36192a08b17a9ed0faf Mon Sep 17 00:00:00 2001 From: Jiayee Lim Date: Wed, 28 Aug 2024 14:42:12 +0800 Subject: [PATCH] chore: remove swagger --- README.md | 1 - backend/Dockerfile | 1 - backend/openapi.yaml | 4905 -------------------- backend/package-lock.json | 35 +- backend/package.json | 2 - backend/src/core/loaders/index.ts | 2 - backend/src/core/loaders/swagger.loader.ts | 51 - backend/src/core/routes/index.ts | 10 - frontend/package-lock.json | 24 - 9 files changed, 2 insertions(+), 5029 deletions(-) delete mode 100644 backend/openapi.yaml delete mode 100644 backend/src/core/loaders/swagger.loader.ts diff --git a/README.md b/README.md index 8afe657a4..fe9b717a5 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,6 @@ You should find the - React frontend at [localhost:3000](http://localhost:3000) - Express backend at [localhost:4000](http://localhost:4000) -- Swagger docs at [localhost:4000/docs](http://localhost:4000/docs) Alternatively, if you would like to develop locally against staging database and workers, ensure that you have set up the necessary variables in `./backend/.env` and run either: diff --git a/backend/Dockerfile b/backend/Dockerfile index ffd68de25..87f99645a 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -47,7 +47,6 @@ RUN npm install COPY --from=builder /usr/home/shared/build ../shared/build -COPY openapi.yaml ./ COPY --from=builder /usr/home/postmangovsg/build ./build ENTRYPOINT [ "tini", "--" ] diff --git a/backend/openapi.yaml b/backend/openapi.yaml deleted file mode 100644 index abc44c561..000000000 --- a/backend/openapi.yaml +++ /dev/null @@ -1,4905 +0,0 @@ -openapi: 3.0.0 -info: - title: Postman - version: v1 - description: Postman API - license: - name: MIT - url: https://choosealicense.com/licenses/mit/ -servers: - - url: /v1 - description: Postman API v1 -security: - - bearerAuth: [] -paths: - /campaigns: - get: - security: - - bearerAuth: [] - tags: - - Campaigns - summary: List all campaigns for user - parameters: - - in: query - name: limit - description: max number of campaigns returned - required: false - schema: - type: integer - minimum: 1 - maximum: 100 - default: 10 - - in: query - name: offset - description: offset to begin returning campaigns from - required: false - schema: - type: integer - minimum: 0 - default: 0 - - in: query - name: type - description: mode of campaigns to filter for - required: false - schema: - $ref: '#/components/schemas/ChannelType' - - in: query - name: status - description: status of campaigns to filter for - required: false - schema: - type: string - enum: [Draft, Sending, Sent] - - in: query - name: name - description: name of campaigns to filter for - required: false - schema: - type: string - - in: query - name: sort_by - description: field used to sort campaigns - required: false - schema: - type: string - enum: [created_at, sent_at] - default: created_at - - in: query - name: order_by - description: order to sort campaigns by - required: false - schema: - type: string - enum: [ASC, DESC] - default: DESC - responses: - '200': - description: List of campaigns - content: - application/json: - schema: - type: object - properties: - campaigns: - type: array - items: - $ref: '#/components/schemas/CampaignMeta' - total_count: - type: integer - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - post: - security: - - bearerAuth: [] - summary: Create a new campaign - tags: - - Campaigns - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - type: - $ref: '#/components/schemas/ChannelType' - required: - - name - - type - - responses: - '201': - description: Campaign created - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignMeta' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaigns/{campaignId}: - delete: - security: - - bearerAuth: [] - tags: - - Campaigns - summary: Delete a campaign using its ID - parameters: - - in: path - name: campaignId - description: ID of the campaign - required: true - schema: - type: integer - minimum: 1 - responses: - '200': - description: Successfully deleted - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignIdObject' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - put: - security: - - bearerAuth: [] - summary: Rename campaign - tags: - - Campaigns - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - should_save_list: - type: boolean - responses: - '200': - description: Campaign renamed - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignMeta' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaigns/{campaignId}/cancel: - post: - security: - - bearerAuth: [] - tags: - - Campaigns - summary: Cancels the scheduling of the campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Successfully cancelled the campaign - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignIdObject' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/email: - get: - security: - - bearerAuth: [] - tags: - - Email - summary: Get email campaign details - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Email campaign details - content: - application/json: - schema: - $ref: '#/components/schemas/EmailCampaign' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/email/template: - put: - security: - - bearerAuth: [] - tags: - - Email - summary: Stores body template for email campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - subject - - body - - reply_to - - from - properties: - subject: - type: string - body: - type: string - minLength: 1 - maxLength: 200 - reply_to: - type: string - nullable: true - from: - type: string - show_logo: - type: boolean - default: true - responses: - 200: - description: Success - content: - application/json: - schema: - required: - - message - - valid - - num_recipients - properties: - message: - type: string - extra_keys: - type: array - items: - type: string - valid: - type: boolean - num_recipients: - type: integer - template: - type: object - properties: - subject: - type: string - body: - type: string - reply_to: - type: string - nullable: true - params: - type: array - items: - type: string - from: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/email/upload/start: - get: - security: - - bearerAuth: [] - summary: 'Get a presigned URL for upload with Content-MD5 header' - tags: - - Email - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - name: mime_type - in: query - required: true - schema: - type: string - - name: md5 - in: query - required: true - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - type: object - required: - - presigned_url - - transaction_id - properties: - presigned_url: - type: string - transaction_id: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/email/upload/complete: - post: - security: - - bearerAuth: [] - summary: 'Complete upload session with ETag verification' - tags: - - Email - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - required: - - transaction_id - - filename - properties: - transaction_id: - type: string - filename: - type: string - etag: - type: string - responses: - '202': - description: Accepted. The uploaded file is being processed. - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignIdObject' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/email/upload/status: - get: - security: - - bearerAuth: [] - summary: 'Get csv processing status' - tags: - - Email - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - properties: - is_csv_processing: - type: boolean - csv_filename: - type: string - temp_csv_filename: - type: string - csv_error: - type: string - num_recipients: - type: number - preview: - type: object - required: - - subject - - body - - from - properties: - subject: - type: string - body: - type: string - replyTo: - type: string - nullable: true - from: - type: string - example: 'Postman ' - showMasthead: - type: boolean - agencyLogoURI: - type: string - example: 'https://file.go.gov.sg/postman-ogp.png' - agencyName: - type: string - example: Open Government Products - themedBody: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - delete: - security: - - bearerAuth: [] - description: 'Deletes error status from previous failed upload' - tags: - - Email - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignIdObject' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/email/credentials: - post: - security: - - bearerAuth: [] - tags: - - Email - summary: Sends a test message and defaults to Postman's credentials for the campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - required: - - recipient - properties: - recipient: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - required: - - message - properties: - message: - type: string - example: 'OK' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/email/preview: - get: - security: - - bearerAuth: [] - tags: - - Email - summary: Preview templated message - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - preview: - type: object - required: - - body - - subject - - from - properties: - body: - type: string - subject: - type: string - reply_to: - type: string - nullable: true - from: - type: string - example: 'Postman ' - themed_body: - type: string - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/send: - post: - security: - - bearerAuth: [] - tags: - - Email - summary: Start sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - job_id: - type: array - items: - type: number - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/retry: - post: - security: - - bearerAuth: [] - tags: - - Email - summary: Retry sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/stats: - get: - security: - - bearerAuth: [] - tags: - - Email - summary: Get email campaign stats - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - allOf: - - $ref: '#/components/schemas/CampaignStats' - - type: object - required: - - unsubscribed - properties: - unsubscribed: - type: number - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/refresh-stats: - post: - security: - - bearerAuth: [] - tags: - - Email - summary: Get email campaign stats - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - allOf: - - $ref: '#/components/schemas/CampaignStats' - - type: object - required: - - unsubscribed - properties: - unsubscribed: - type: number - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/export: - get: - security: - - bearerAuth: [] - tags: - - Email - summary: Get recipients of campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: array - items: - allOf: - - $ref: '#/components/schemas/CampaignRecipient' - - type: object - properties: - 'unsubscriber.recipient': - type: string - 'unsubscriber.reason': - type: string - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '410': - description: Data No Longer Available - content: - application/json: - schema: - $ref: '#/components/schemas/Error410Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/protect/upload/start: - get: - security: - - bearerAuth: [] - tags: - - Email - summary: Start multipart upload - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - name: mime_type - in: query - required: true - schema: - type: string - - name: part_count - in: query - required: true - schema: - type: integer - minimum: 1 - maximum: 100 - default: 1 - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - transaction_id: - type: string - presigned_urls: - type: array - items: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/protect/upload/complete: - post: - security: - - bearerAuth: [] - summary: Complete multipart upload - tags: - - Email - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - required: - - filename - - transaction_id - - part_count - - etags - properties: - filename: - type: string - transaction_id: - type: string - part_count: - type: integer - etags: - type: array - items: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - transaction_id: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/duplicate: - post: - security: - - bearerAuth: [] - tags: - - Email - summary: Duplicate the campaign and its template - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - name - properties: - name: - type: string - - responses: - '201': - description: A duplicate of the campaign was created - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignDuplicateMeta' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/email/select-list: - post: - security: - - bearerAuth: [] - tags: - - Email - summary: Select the list of recipients from an existing managed list - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - list_id: - type: number - responses: - '201': - description: A duplicate of the campaign was created - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignMeta' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /transactional/email/send: - post: - security: - - bearerAuth: [] - summary: 'Send a transactional email' - tags: - - Email - requestBody: - content: - application/json: - schema: - required: - - subject - - body - - recipient - properties: - subject: - type: string - body: - type: string - recipient: - type: string - cc: - type: array - items: - type: string - bcc: - type: array - items: - type: string - from: - type: string - reply_to: - type: string - classification: - type: string - enum: [URGENT, FOR_ACTION, FOR_INFO] - tag: - type: string - multipart/form-data: - schema: - type: object - required: - - subject - - body - - recipient - properties: - subject: - type: string - body: - type: string - recipient: - type: string - cc: - type: array - items: - type: string - bcc: - type: array - items: - type: string - from: - type: string - reply_to: - type: string - attachments: - type: array - items: - type: string - format: binary - classification: - type: string - enum: [URGENT, FOR_ACTION, FOR_INFO] - tag: - type: string - responses: - '201': - description: Created. The message is being sent. - content: - application/json: - schema: - $ref: '#/components/schemas/EmailMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '413': - description: Number of attachments or size of attachments exceeded limit. - content: - application/json: - schema: - $ref: '#/components/schemas/Error413Response' - '429': - description: Rate limit exceeded. Too many requests. - content: - application/json: - schema: - $ref: '#/components/schemas/Error429Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /transactional/email: - get: - security: - - bearerAuth: [] - tags: - - Email - summary: 'List transactional emails' - parameters: - - in: query - name: limit - description: max number of messages returned - required: false - schema: - type: integer - minimum: 1 - maximum: 100 - default: 10 - - in: query - name: offset - description: offset to begin returning messages from - required: false - schema: - type: integer - minimum: 0 - default: 0 - - in: query - name: status - description: status of messages to filter for - required: false - schema: - type: array - items: - type: string - enum: - [UNSENT, ACCEPTED, SENT, BOUNCED, DELIVERED, OPENED, COMPLAINT] - style: form - explode: true - - in: query - name: created_at - description: > - Filter for created_at timestamp of messages: - - gt: greater than - - gte: greater than or equal - - lt: less than - - lte: less than or equal - required: false - schema: - type: object - minProperties: 1 - properties: - gt: - type: string - format: date-time - gte: - type: string - format: date-time - lt: - type: string - format: date-time - lte: - type: string - format: date-time - - in: query - name: sort_by - description: > - Array of fields to sort by, default order is desc, but can be configured by adding a prefix of: - - plus sign (+) for ascending order - - minus sign (-) for descending order - required: false - schema: - type: array - default: [created_at] - items: - type: string - enum: - [ - created_at, - +created_at, - -created_at, - updated_at, - -updated_at, - +updated_at, - ] - - responses: - 200: - description: Successfully retrieved a list of messages - content: - application/json: - schema: - type: object - required: - - has_more - - data - properties: - has_more: - type: boolean - data: - type: array - items: - $ref: '#/components/schemas/EmailMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /transactional/email/{emailId}: - get: - security: - - bearerAuth: [] - tags: - - Email - summary: 'Get transactional email by ID' - parameters: - - in: path - name: emailId - required: true - schema: - type: string - example: 42 - responses: - 200: - description: Successfully retrieved transactional email with corresponding ID - content: - application/json: - schema: - $ref: '#/components/schemas/EmailMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/govsg: - get: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Get GovSG campaign details - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: GovSG campaign details - content: - application/json: - schema: - $ref: '#/components/schemas/GovSGCampaign' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /govsg/templates: - get: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Get available templates for GovSG channel - responses: - 200: - description: Success - content: - application/json: - schema: - required: - - data - properties: - data: - type: array - items: - $ref: '#/components/schemas/GovSGTemplate' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/templates: - put: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Choose a template for a govsg campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - template_id: - type: number - language_code: - type: string - default: en_GB - responses: - 200: - description: Success - content: - application/json: - schema: - required: - - data - properties: - data: - $ref: '#/components/schemas/GovSGCampaign' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/upload/start: - get: - security: - - bearerAuth: [] - summary: 'Get a presigned URL for upload with Content-MD5 header' - tags: - - GovSG - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - name: mime_type - in: query - required: true - schema: - type: string - - name: md5 - in: query - required: true - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - type: object - required: - - presigned_url - - transaction_id - properties: - presigned_url: - type: string - transaction_id: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/upload/status: - get: - security: - - bearerAuth: [] - summary: 'Get csv processing status' - tags: - - GovSG - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - properties: - is_csv_processing: - type: boolean - csv_filename: - type: string - temp_csv_filename: - type: string - csv_error: - type: string - num_recipients: - type: number - preview: - type: object - required: - - body - properties: - body: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - delete: - security: - - bearerAuth: [] - description: 'Deletes error status from previous failed upload' - tags: - - GovSG - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignIdObject' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/preview: - get: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Preview templated message - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - preview: - type: object - properties: - body: - type: string - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/send: - post: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Start sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - job_id: - type: array - items: - type: number - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/retry: - post: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Retry sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/stats: - get: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Get GovSG campaign stats - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignStats' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/refresh-stats: - post: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Forcibly refresh GovSG campaign stats, then retrieves them - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignStats' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/export: - get: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Get invalid recipients in campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/CampaignRecipient' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '410': - description: Data No Longer Available - content: - application/json: - schema: - $ref: '#/components/schemas/Error410Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/govsg/duplicate: - post: - security: - - bearerAuth: [] - tags: - - GovSG - summary: Duplicate the campaign and its choice of template - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - name - properties: - name: - type: string - responses: - '201': - description: A duplicate of the campaign was created - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignDuplicateMeta' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /transactional/govsg/send: - post: - security: - - bearerAuth: [] - summary: 'Send a transactional GovSG message' - tags: - - GovSG - requestBody: - content: - application/json: - schema: - required: - - recipient - - template_id - - params - properties: - recipient: - type: string - description: > - Mobile phone number of the recipient without special formatting - (only contains numerical characters and prefixed with plus - sign if country code is included). - - - **Notes**: - - Country code will need to be provided for non-SG mobile numbers. - - If country code is not provided, the phone number will be defaulted to be an SG number. - example: '81234567' - template_id: - type: number - example: 2 - language_code: - type: string - default: en_GB - params: - type: object - additionalProperties: - type: string - example: { officer_name: 'John Tan' } - responses: - '201': - description: Created. The message is being sent. - content: - application/json: - schema: - $ref: '#/components/schemas/GovSGMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '429': - description: Rate limit exceeded. Too many requests. - content: - application/json: - schema: - $ref: '#/components/schemas/Error429Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /transactional/govsg: - get: - security: - - bearerAuth: [] - tags: - - GovSG - summary: 'List transactional GovSG messages' - parameters: - - in: query - name: limit - description: max number of messages returned - required: false - schema: - type: integer - minimum: 1 - maximum: 100 - default: 10 - - in: query - name: offset - description: offset to begin returning messages from - required: false - schema: - type: integer - minimum: 0 - default: 0 - - in: query - name: status - description: status of messages to filter for - required: false - schema: - type: array - items: - type: string - enum: [UNSENT, ACCEPTED, SENT, DELIVERED, READ, ERROR] - style: form - explode: true - - in: query - name: created_at - description: > - Filter for created_at timestamp of messages: - - - gt: greater than - - gte: greater than or equal - - lt: less than - - lte: less than or equal - required: false - schema: - type: object - minProperties: 1 - properties: - gt: - type: string - format: date-time - gte: - type: string - format: date-time - lt: - type: string - format: date-time - lte: - type: string - format: date-time - - in: query - name: sort_by - description: > - Array of fields to sort by, default order is desc, but can be configured by adding a prefix of: - - - plus sign (+) for ascending order - - minus sign (-) for descending order - required: false - schema: - type: array - default: [created_at] - items: - type: string - enum: - [ - created_at, - +created_at, - -created_at, - updated_at, - -updated_at, - +updated_at, - ] - - responses: - 200: - description: Successfully retrieved a list of messages - content: - application/json: - schema: - type: object - required: - - has_more - - data - properties: - has_more: - type: boolean - data: - type: array - items: - $ref: '#/components/schemas/GovSGMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /transactional/govsg/{messageId}: - get: - security: - - bearerAuth: [] - tags: - - GovSG - summary: 'Get transactional GovSG by ID' - parameters: - - in: path - name: messageId - required: true - schema: - type: string - example: 42 - responses: - 200: - description: Successfully retrieved transactional GovSG message with corresponding ID - content: - application/json: - schema: - $ref: '#/components/schemas/GovSGMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/sms: - get: - security: - - bearerAuth: [] - tags: - - SMS - summary: Get sms campaign details - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Successfully retrieved sms campaign details - content: - application/json: - schema: - allOf: - - $ref: '#/components/schemas/SMSCampaign' - - type: object - properties: - cost_per_message: - type: number - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/template: - put: - security: - - bearerAuth: [] - tags: - - SMS - summary: Stores body template for sms campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - body: - type: string - minLength: 1 - maxLength: 200 - - responses: - 200: - description: Success - content: - application/json: - schema: - required: - - message - - valid - - num_recipients - - template - properties: - message: - type: string - extra_keys: - type: array - items: - type: string - valid: - type: boolean - num_recipients: - type: integer - template: - type: object - properties: - body: - type: string - params: - type: array - items: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/upload/start: - get: - security: - - bearerAuth: [] - summary: 'Get a presigned URL for upload with Content-MD5 header' - tags: - - SMS - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - name: mime_type - in: query - required: true - schema: - type: string - - name: md5 - required: true - in: query - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - type: object - properties: - presigned_url: - type: string - transaction_id: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/upload/complete: - post: - security: - - bearerAuth: [] - summary: 'Complete upload session with ETag verification' - tags: - - SMS - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - required: - - transaction_id - - filename - properties: - transaction_id: - type: string - filename: - type: string - etag: - type: string - responses: - '202': - description: Accepted. The uploaded file is being processed. - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/upload/status: - get: - security: - - bearerAuth: [] - summary: 'Get csv processing status' - tags: - - SMS - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - properties: - is_csv_processing: - type: boolean - csv_filename: - type: string - temp_csv_filename: - type: string - csv_error: - type: string - num_recipients: - type: number - preview: - type: object - properties: - body: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - delete: - security: - - bearerAuth: [] - description: 'Deletes error status from previous failed upload' - tags: - - SMS - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/new-credentials: - post: - security: - - bearerAuth: [] - tags: - - SMS - summary: Validate twilio credentials and assign to campaign, if label is provided - store credentials for user - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - allOf: - - $ref: '#/components/schemas/TwilioCredentials' - - type: object - properties: - recipient: - type: string - label: - type: string - pattern: '/^[a-z0-9-]+$/' - minLength: 1 - maxLength: 50 - description: should only consist of lowercase alphanumeric characters and dashes - responses: - 200: - description: OK - content: - application/json: - schema: - type: object - required: - - message - properties: - message: - type: string - example: OK - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/credentials: - post: - security: - - bearerAuth: [] - tags: - - SMS - summary: Validate stored credentials and assign to campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - recipient: - type: string - label: - type: string - responses: - 200: - description: OK - content: - application/json: - schema: - type: object - required: - - message - properties: - message: - type: string - example: OK - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/preview: - get: - security: - - bearerAuth: [] - tags: - - SMS - summary: Preview templated message - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - preview: - type: object - properties: - body: - type: string - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/send: - post: - security: - - bearerAuth: [] - tags: - - SMS - summary: Start sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - rate: - example: 10 - type: integer - minimum: 1 - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - job_id: - type: array - items: - type: number - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/retry: - post: - security: - - bearerAuth: [] - tags: - - SMS - summary: Retry sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/stats: - get: - security: - - bearerAuth: [] - tags: - - SMS - summary: Get sms campaign stats - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignStats' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/refresh-stats: - post: - security: - - bearerAuth: [] - tags: - - SMS - summary: Forcibly refresh sms campaign stats, then retrieves them - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: Success - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignStats' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/export: - get: - security: - - bearerAuth: [] - tags: - - SMS - summary: Get invalid recipients in campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/CampaignRecipient' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '410': - description: Data No Longer Available - content: - application/json: - schema: - $ref: '#/components/schemas/Error410Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/duplicate: - post: - security: - - bearerAuth: [] - tags: - - SMS - summary: Duplicate the campaign and its template - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - required: - - name - properties: - name: - type: string - responses: - '201': - description: A duplicate of the campaign was created - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignDuplicateMeta' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/sms/select-list: - post: - security: - - bearerAuth: [] - tags: - - SMS - summary: Select the list of recipients from an existing managed list - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - list_id: - type: number - - responses: - '201': - description: A duplicate of the campaign was created - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /transactional/sms/send: - post: - security: - - bearerAuth: [] - summary: 'Send a transactional SMS' - tags: - - SMS - requestBody: - content: - application/json: - schema: - required: - - body - - recipient - - label - properties: - body: - type: string - recipient: - type: string - label: - type: string - responses: - '201': - description: Created. The message is being sent. - content: - application/json: - schema: - $ref: '#/components/schemas/SmsMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '429': - description: Rate limit exceeded. Too many requests. - content: - application/json: - schema: - $ref: '#/components/schemas/Error429Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /transactional/sms: - get: - security: - - bearerAuth: [] - tags: - - SMS - summary: 'List transactional SMSes' - parameters: - - in: query - name: limit - description: max number of messages returned - required: false - schema: - type: integer - minimum: 1 - maximum: 100 - default: 10 - - in: query - name: offset - description: offset to begin returning messages from - required: false - schema: - type: integer - minimum: 0 - default: 0 - - in: query - name: status - description: status of messages to filter for - required: false - schema: - type: array - items: - type: string - enum: [UNSENT, ACCEPTED, SENT, DELIVERED, ERROR] - style: form - explode: true - - in: query - name: created_at - description: > - Filter for created_at timestamp of messages: - - gt: greater than - - gte: greater than or equal - - lt: less than - - lte: less than or equal - required: false - schema: - type: object - minProperties: 1 - properties: - gt: - type: string - format: date-time - gte: - type: string - format: date-time - lt: - type: string - format: date-time - lte: - type: string - format: date-time - - in: query - name: sort_by - description: > - Array of fields to sort by, default order is desc, but can be configured by adding a prefix of: - - plus sign (+) for ascending order - - minus sign (-) for descending order - required: false - schema: - type: array - default: [created_at] - items: - type: string - enum: - [ - created_at, - +created_at, - -created_at, - updated_at, - -updated_at, - +updated_at, - ] - - responses: - 200: - description: Successfully retrieved a list of messages - content: - application/json: - schema: - type: object - required: - - has_more - - data - properties: - has_more: - type: boolean - data: - type: array - items: - $ref: '#/components/schemas/SmsMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /transactional/sms/{smsId}: - get: - security: - - bearerAuth: [] - tags: - - SMS - summary: 'Get transactional SMS by ID' - parameters: - - in: path - name: smsId - required: true - schema: - type: string - example: 42 - responses: - 200: - description: Successfully retrieved transactional SMS with corresponding ID - content: - application/json: - schema: - $ref: '#/components/schemas/SmsMessageTransactional' - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - /campaign/{campaignId}/telegram: - get: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Get telegram campaign details - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - campaign: - $ref: '#/components/schemas/TelegramCampaign' - num_recipients: - type: number - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/template: - put: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Stores body template for telegram campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - body: - type: string - minLength: 1 - maxLength: 200 - - responses: - 200: - description: Success - content: - application/json: - schema: - required: - - message - - valid - - num_recipients - - template - properties: - message: - type: string - extra_keys: - type: array - items: - type: string - valid: - type: boolean - num_recipients: - type: integer - template: - type: object - properties: - body: - type: string - params: - type: array - items: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/upload/start: - get: - security: - - bearerAuth: [] - summary: 'Get a presigned URL for upload with Content-MD5 header' - tags: - - Telegram - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - name: mime_type - in: query - required: true - schema: - type: string - - name: md5 - required: true - in: query - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - type: object - properties: - presigned_url: - type: string - transaction_id: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/upload/complete: - post: - security: - - bearerAuth: [] - summary: 'Complete upload session with ETag verification' - tags: - - Telegram - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - required: - - transaction_id - - filename - properties: - transaction_id: - type: string - filename: - type: string - etag: - type: string - responses: - '202': - description: Accepted. The uploaded file is being processed. - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/upload/status: - get: - security: - - bearerAuth: [] - summary: 'Get csv processing status' - tags: - - Telegram - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - 200: - description: Success - content: - application/json: - schema: - properties: - is_csv_processing: - type: boolean - csv_filename: - type: string - temp_csv_filename: - type: string - csv_error: - type: string - num_recipients: - type: number - preview: - type: object - properties: - body: - type: string - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - delete: - security: - - bearerAuth: [] - description: 'Deletes error status from previous failed upload' - tags: - - Telegram - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - 200: - description: Success - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/preview: - get: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Preview templated message - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: Success - content: - application/json: - schema: - type: object - properties: - preview: - type: object - properties: - body: - type: string - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/new-credentials: - post: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Validate Telegram bot token and assign to campaign, if label is provided store new telegram credentials for user - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - telegram_bot_token: - type: string - label: - type: string - pattern: '/^[a-z0-9-]+$/' - minLength: 1 - maxLength: 50 - description: should only consist of lowercase alphanumeric characters and dashes - responses: - 200: - description: OK - content: - application/json: - schema: - type: object - required: - - message - properties: - message: - type: string - example: OK - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/credentials: - post: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Validate stored credentials and assign to campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - label: - type: string - - responses: - 200: - description: OK - content: - application/json: - schema: - type: object - required: - - message - properties: - message: - type: string - example: OK - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/credentials/verify: - post: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Send a validation message using the campaign credentials. - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - recipient: - type: string - responses: - 200: - description: OK - content: - application/json: - schema: - type: object - required: - - message - properties: - message: - type: string - example: OK - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/send: - post: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Start sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: false - content: - application/json: - schema: - type: object - properties: - rate: - type: integer - default: 30 - minimum: 1 - maximum: 30 - - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - job_id: - type: array - items: - type: number - '400': - description: Bad Request - content: - application/json: - schema: - $ref: '#/components/schemas/Error400Response' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/retry: - post: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Retry sending campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - responses: - '200': - description: OK - content: - application/json: - schema: - type: object - properties: - campaign_id: - type: integer - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/stats: - get: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Get telegram campaign stats - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignStats' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/refresh-stats: - post: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Get telegram campaign stats - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: OK - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignStats' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/export: - get: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Get invalid recipients in campaign - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - - responses: - '200': - description: OK - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/CampaignRecipient' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '410': - description: Data No Longer Available - content: - application/json: - schema: - $ref: '#/components/schemas/Error410Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - - /campaign/{campaignId}/telegram/duplicate: - post: - security: - - bearerAuth: [] - tags: - - Telegram - summary: Duplicate the campaign and its template - parameters: - - name: campaignId - in: path - required: true - schema: - type: string - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - name: - type: string - - responses: - '201': - description: A duplicate of the campaign was created - content: - application/json: - schema: - $ref: '#/components/schemas/CampaignDuplicateMeta' - '401': - description: Unauthenticated - content: - application/json: - schema: - $ref: '#/components/schemas/Error401Response' - '403': - description: Unauthorized - content: - application/json: - schema: - $ref: '#/components/schemas/Error403Response' - '404': - description: Not Found - content: - application/json: - schema: - $ref: '#/components/schemas/Error404Response' - '500': - description: Internal Server Error - content: - application/json: - schema: - $ref: '#/components/schemas/Error500Response' - -components: - securitySchemes: - bearerAuth: - type: http - description: API key to authorize requests. - scheme: bearer - schemas: - ChannelType: - type: string - enum: - - SMS - - EMAIL - - TELEGRAM - - GOVSG - - CampaignIdObject: - type: object - required: - - id - properties: - id: - type: string - example: '20' - CampaignMeta: - type: object - properties: - id: - type: number - name: - type: string - created_at: - type: string - format: date-time - has_credential: - type: boolean - valid: - type: boolean - halted: - type: boolean - protect: - type: boolean - redacted: - type: boolean - should_save_list: - type: boolean - type: - $ref: '#/components/schemas/ChannelType' - job_queue: - type: array - items: - $ref: '#/components/schemas/JobQueue' - - CampaignDuplicateMeta: - type: object - required: - - name - - id - - created_at - - type - - protect - properties: - id: - type: number - name: - type: string - type: - $ref: '#/components/schemas/ChannelType' - created_at: - type: string - format: date-time - protect: - type: boolean - example: false - - JobQueue: - type: object - properties: - status: - $ref: '#/components/schemas/JobStatus' - sent_at: - type: string - format: date-time - status_updated_at: - type: string - format: date-time - - JobStatus: - type: string - enum: - - READY - - ENQUEUED - - SENDING - - SENT - - STOPPED - - LOGGED - ErrorStatus: - type: object - properties: - status: - type: integer - message: - type: string - EmailCampaign: - type: object - properties: - id: - type: number - name: - type: string - created_at: - type: string - format: date-time - has_credential: - type: boolean - valid: - type: boolean - protect: - type: boolean - redacted: - type: boolean - csv_filename: - type: string - is_csv_processing: - type: boolean - num_recipients: - type: number - type: - $ref: '#/components/schemas/ChannelType' - default: 'EMAIL' - job_queue: - type: array - items: - $ref: '#/components/schemas/JobQueue' - email_templates: - type: object - properties: - body: - type: string - subject: - type: string - params: - type: array - items: - type: string - GovSGCampaign: - type: object - properties: - id: - type: number - name: - type: string - created_at: - type: string - format: date-time - has_credential: - type: boolean - valid: - type: boolean - protect: - type: boolean - redacted: - type: boolean - csv_filename: - type: string - is_csv_processing: - type: boolean - num_recipients: - type: number - type: - $ref: '#/components/schemas/ChannelType' - default: 'GOVSG' - job_queue: - type: array - items: - $ref: '#/components/schemas/JobQueue' - govsg_templates: - $ref: '#/components/schemas/GovSGTemplate' - GovSGTemplate: - type: object - required: - - id - - body - - params - properties: - id: - type: number - body: - type: string - params: - type: array - items: - type: string - multilingual_support: - type: array - items: - type: object - required: - - language_code - - language - - body - properties: - language_code: - type: string - example: zh_CN - language: - type: string - example: Chinese (CHN) - body: - type: string - CampaignStats: - type: object - properties: - error: - type: number - unsent: - type: number - sent: - type: number - invalid: - type: number - halted: - type: boolean - redacted: - type: boolean - status: - $ref: '#/components/schemas/JobStatus' - updated_at: - type: string - format: date-time - CampaignRecipient: - type: object - properties: - recipient: - type: string - status: - type: string - updated_at: - type: string - format: date-time - error_code: - type: string - EmailMessageTransactional: - type: object - properties: - id: - type: string - example: 42 - from: - type: string - example: Postman - recipient: - type: string - example: hello@example.com - params: - type: object - properties: - body: - type: string - example: Hello World - from: - type: string - example: Postman - subject: - type: string - example: Hello World - reply_to: - type: string - example: hello@example.com - attachments_metadata: - nullable: true - type: array - items: - type: object - required: - - fileName - - fileSize - - hash - properties: - fileName: - type: string - fileSize: - type: number - hash: - type: string - status: - type: string - enum: [UNSENT, ACCEPTED, SENT, BOUNCED, DELIVERED, OPENED, COMPLAINT] - description: > - * `UNSENT` - initial state of a newly created transactional email (this status is not returned in the course of a successful request to send an email) - - * `ACCEPTED` - email has been accepted by our email provider (this status is returned in the course of a successful request to send an email) - - * `SENT` - the send request was successfully forwarded to our email provider and our email provider will attempt to deliver the message to the recipient’s mail server (API user can check this and all subsequent statuses via the `/transactional/email/{emailId}` endpoint) - - * `BOUNCED` - the recipient's mail server rejected the email - - * `DELIVERED` - the email provider has successfully delivered the email to the recipient's mail server - - * `OPENED` - the recipient received the message and opened it in their email client - - * `COMPLAINT` - the email was successfully delivered to the recipient’s mail server, but the recipient marked it as spam - error_code: - nullable: true - type: string - error_sub_type: - nullable: true - type: string - created_at: - nullable: false - type: string - format: date-time - updated_at: - nullable: true - type: string - format: date-time - accepted_at: - nullable: true - type: string - format: date-time - sent_at: - nullable: true - type: string - format: date-time - delivered_at: - nullable: true - type: string - format: date-time - opened_at: - nullable: true - type: string - format: date-time - TwilioCredentials: - type: object - properties: - twilio_account_sid: - type: string - twilio_api_key: - type: string - twilio_api_secret: - type: string - twilio_messaging_service_sid: - type: string - SMSCampaign: - type: object - properties: - id: - type: number - name: - type: string - created_at: - type: string - format: date-time - has_credential: - type: boolean - valid: - type: boolean - redacted: - type: boolean - csv_filename: - type: string - is_csv_processing: - type: boolean - num_recipients: - type: number - type: - $ref: '#/components/schemas/ChannelType' - default: 'SMS' - job_queue: - type: array - items: - $ref: '#/components/schemas/JobQueue' - sms_templates: - type: object - properties: - body: - type: string - params: - type: array - items: - type: string - SmsMessageTransactional: - type: object - properties: - id: - type: string - example: 42 - credentials_label: - type: string - example: 'ogp-twilio-creds' - recipient: - type: string - example: '98765432' - body: - type: string - example: 'Hello world' - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - accepted_at: - type: string - format: date-time - sent_at: - type: string - format: date-time - delivered_at: - type: string - format: date-time - errored_at: - type: string - format: date-time - error_code: - type: string - description: This error code corresponds with [error codes from Twilio](https://www.twilio.com/docs/sms/api/message-resource#delivery-related-errors). - status: - type: string - enum: [UNSENT, ACCEPTED, SENT, DELIVERED, ERROR] - description: > - * `UNSENT` - initial state of a newly created transactional SMS (this status is not returned in the course of a successful request to send an SMS) - - * `ACCEPTED` - SMS has been accepted by our SMS provider (this status is returned in the course of a successful request to send an SMS) - - * `SENT` - the send request was successfully forwarded to our SMS provider and our SMS provider will attempt to deliver the message to the recipient’s phone number (API user can check this and all subsequent statuses via the `/transactional/sms/{smsId}` endpoint) - - * `DELIVERED` - the SMS provider has successfully delivered the SMS to the recipient's phone number - - * `ERROR` - an error happened when the SMS provider is trying to deliver the message - GovSGMessageTransactional: - type: object - properties: - id: - type: string - example: 42 - recipient: - type: string - example: '98765432' - template_id: - type: number - example: 2 - params: - type: object - additionalProperties: - type: string - language_code: - type: string - example: en_GB - created_at: - type: string - format: date-time - updated_at: - type: string - format: date-time - accepted_at: - type: string - format: date-time - sent_at: - type: string - format: date-time - delivered_at: - type: string - format: date-time - read_at: - type: string - format: date-time - errored_at: - type: string - format: date-time - error_code: - type: string - description: > - This error code corresponds with error codes from our service providers: - - [WhatsApp](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/#error-codes) - error_description: - type: string - description: Human-readable details about the message error. - status: - type: string - enum: [UNSENT, ACCEPTED, SENT, DELIVERED, ERROR] - description: > - * `UNSENT` - initial state of a newly created transactional GovSG message (this status is not returned in the course of a successful request to send a GovSG message) - - * `ACCEPTED` - Message has been accepted by our service provider (this status is returned in the course of a successful request to send a GovSG message) - - * `SENT` - the send request was successfully forwarded to our service provider and our service provider will attempt to deliver the message to the recipient’s phone number (API user can check this and all subsequent statuses via the `/transactional/govSG/{messageId}` endpoint) - - * `DELIVERED` - the service provider has successfully delivered the message to the recipient's phone number - - * `READ` - the recipient has received the message and viewed it - - * `ERROR` - an error happened when the service provider is trying to deliver the message - TelegramCampaign: - type: object - properties: - id: - type: number - name: - type: string - created_at: - type: string - format: date-time - has_credential: - type: boolean - valid: - type: boolean - redacted: - type: boolean - csv_filename: - type: string - type: - $ref: '#/components/schemas/ChannelType' - default: 'TELEGRAM' - job_queue: - type: array - items: - $ref: '#/components/schemas/JobQueue' - telegram_templates: - type: object - properties: - body: - type: string - params: - type: array - items: - type: string - Error401Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: ['unathenticated'] - message: - type: string - example: Unauthenticated request. Please try again with correct authentication - Error500Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: ['internal_server'] - message: - type: string - example: Intetnal server error. Please try again later - Error404Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: ['not_found'] - message: - type: string - example: Campaign with ID 20 not found. - Error403Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: ['unauthorized', 'already_sent'] - message: - type: string - example: Campaign can't be edited at the moment as there're ongoing uploads or jobs - Error400Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: - [ - 'api_validation', - 'invalid_recipient', - 'invalid_credentials', - 'malformed', - 'invalid_parameters', - 'invalid_from_address', - 'invalid_template', - 'invalid_credential_label', - ] - message: - type: string - example: Phone number 84206920 is invalid - Error410Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: ['campaign_redacted'] - message: - type: string - example: Campaign 20 has been redacted - Error413Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: ['attachment_limit'] - message: - type: string - example: Size of attachments exceeds limit - Error429Response: - type: object - required: - - code - - message - properties: - code: - type: string - enum: ['rate_limit'] - message: - type: string - example: Too many requests. Please try again later. diff --git a/backend/package-lock.json b/backend/package-lock.json index 548a1d3e6..ca539d108 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -39,7 +39,7 @@ "module-alias": "2.2.2", "moment": "^2.29.4", "nanoid": "3.3.6", - "nodemailer": "^6.9.9", + "nodemailer": "6.9.9", "papaparse": "5.2.0", "pg": "8.5.1", "pg-connection-string": "2.4.0", @@ -47,10 +47,9 @@ "redis": "3.1.2", "reflect-metadata": "0.1.13", "sequelize": "6.29.1", - "sequelize-typescript": "^2.1.6", + "sequelize-typescript": "2.1.6", "source-map-support": "0.5.19", "starkbank-ecdsa": "1.1.4", - "swagger-ui-express": "4.6.3", "telegraf": "3.38.0", "threads": "1.7.0", "tiny-worker": "2.3.0", @@ -88,7 +87,6 @@ "@types/rate-limit-redis": "1.7.1", "@types/redis": "2.8.17", "@types/supertest": "2.0.12", - "@types/swagger-ui-express": "4.1.2", "@types/umzug": "2.3.0", "@types/uuid": "7.0.2", "@types/validator": "12.0.1", @@ -8839,16 +8837,6 @@ "@types/superagent": "*" } }, - "node_modules/@types/swagger-ui-express": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@types/swagger-ui-express/-/swagger-ui-express-4.1.2.tgz", - "integrity": "sha512-t9teFTU8dKe69rX9EwL6OM2hbVquYdFM+sQ0REny4RalPlxAm+zyP04B12j4c7qEuDS6CnlwICywqWStPA3v4g==", - "dev": true, - "dependencies": { - "@types/express": "*", - "@types/serve-static": "*" - } - }, "node_modules/@types/triple-beam": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", @@ -16767,25 +16755,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/swagger-ui-dist": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.18.2.tgz", - "integrity": "sha512-oVBoBl9Dg+VJw8uRWDxlyUyHoNEDC0c1ysT6+Boy6CTgr2rUcLcfPon4RvxgS2/taNW6O0+US+Z/dlAsWFjOAQ==" - }, - "node_modules/swagger-ui-express": { - "version": "4.6.3", - "resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.6.3.tgz", - "integrity": "sha512-CDje4PndhTD2HkgyKH3pab+LKspDeB/NhPN2OF1j+piYIamQqBYwAXWESOT1Yju2xFg51bRW9sUng2WxDjzArw==", - "dependencies": { - "swagger-ui-dist": ">=4.11.0" - }, - "engines": { - "node": ">= v0.10.32" - }, - "peerDependencies": { - "express": ">=4.0.0 || >=5.0.0-beta" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", diff --git a/backend/package.json b/backend/package.json index 6e0e864c8..5001bae78 100644 --- a/backend/package.json +++ b/backend/package.json @@ -70,7 +70,6 @@ "sequelize-typescript": "2.1.6", "source-map-support": "0.5.19", "starkbank-ecdsa": "1.1.4", - "swagger-ui-express": "4.6.3", "telegraf": "3.38.0", "threads": "1.7.0", "tiny-worker": "2.3.0", @@ -108,7 +107,6 @@ "@types/rate-limit-redis": "1.7.1", "@types/redis": "2.8.17", "@types/supertest": "2.0.12", - "@types/swagger-ui-express": "4.1.2", "@types/umzug": "2.3.0", "@types/uuid": "7.0.2", "@types/validator": "12.0.1", diff --git a/backend/src/core/loaders/index.ts b/backend/src/core/loaders/index.ts index 1314e21ef..688e04bf9 100644 --- a/backend/src/core/loaders/index.ts +++ b/backend/src/core/loaders/index.ts @@ -1,7 +1,6 @@ import { Application } from 'express' import securityHeadersLoader from './security-headers.loader' import expressLoader from './express.loader' -import swaggerLoader from './swagger.loader' import sessionLoader from './session.loader' import sequelizeLoader from './sequelize.loader' import cloudwatchLoader from './cloudwatch.loader' @@ -22,7 +21,6 @@ const loaders = async ({ app }: { app: Application }): Promise => { await sequelizeLoader() await sessionLoader({ app }) await expressLoader({ app }) - await swaggerLoader({ app }) await uploadQueueLoader() ;(app as any).cleanup = async function (): Promise { await (app as any).redisService.shutdown() diff --git a/backend/src/core/loaders/swagger.loader.ts b/backend/src/core/loaders/swagger.loader.ts deleted file mode 100644 index 4a18122b6..000000000 --- a/backend/src/core/loaders/swagger.loader.ts +++ /dev/null @@ -1,51 +0,0 @@ -import express, { Application, Request, Response, NextFunction } from 'express' -import cors from 'cors' -import path from 'path' -import swaggerUi from 'swagger-ui-express' -import YAML from 'yamljs' - -import { loggerWithLabel } from '@core/logger' - -const logger = loggerWithLabel(module) - -const swaggerUiOptions = { - explorer: false, - customCss: '.swagger-ui .topbar { display: none; }', - url: '/v1/swagger.json', -} - -const removeCspHeader = ( - _req: Request, - res: Response, - next: NextFunction -): void => { - res.removeHeader('Content-Security-Policy') - next() -} - -const swaggerDocument = YAML.load( - path.resolve(__dirname, '../../../openapi.yaml') -) - -const swaggerLoader = ({ app }: { app: Application }): void => { - app.get('/v1/swagger.json', (_req, res) => res.json(swaggerDocument)) - app.use( - '/docs', - removeCspHeader, - swaggerUi.serve, - swaggerUi.setup(swaggerDocument, swaggerUiOptions) - ) - app.use( - '/openapi.yaml', - cors({ - origin: '*', - methods: ['GET'], - }), - express.static(path.resolve(__dirname, '../../../openapi.yaml')) - ) - logger.info({ - message: 'Swagger docs generated.', - }) -} - -export default swaggerLoader diff --git a/backend/src/core/routes/index.ts b/backend/src/core/routes/index.ts index 662078d0f..2d77e620c 100644 --- a/backend/src/core/routes/index.ts +++ b/backend/src/core/routes/index.ts @@ -184,16 +184,6 @@ export const InitV1Route = (app: Application): Router => { router.use('/protect', protectedMailRoutes) router.use('/unsubscribe', unsubscriberRoutes) - /** - * @swagger - * components: - * securitySchemes: - * bearerAuth: - * type: http - * scheme: bearer - * bearerFormat: username_versionNumber_apiKey - */ - router.use( '/campaigns', authMiddleware.getAuthMiddleware([AuthType.Cookie, AuthType.ApiKey]), diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b2c332c60..6121a51bd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -6295,16 +6295,6 @@ "ajv": "^6.9.1" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -9170,20 +9160,6 @@ "node": ">=10.13.0" } }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",