From 55d6c75ec4e6a1a21fa229a2bad0007d0c3fd694 Mon Sep 17 00:00:00 2001 From: Ganna Bielanova Date: Mon, 4 May 2026 11:49:47 +0300 Subject: [PATCH 1/5] MT-21122: updated responces --- specs/account-management.openapi.yml | 107 +++++++----- specs/contacts.openapi.yml | 41 ++++- specs/email-sending-bulk.openapi.yml | 26 ++- specs/email-sending-transactional.openapi.yml | 26 ++- specs/email-sending.openapi.yml | 109 +++++++----- specs/sandbox-sending.openapi.yml | 45 ++++- specs/sandbox.openapi.yml | 163 +++++------------- specs/templates.openapi.yml | 90 ++++++---- 8 files changed, 360 insertions(+), 247 deletions(-) diff --git a/specs/account-management.openapi.yml b/specs/account-management.openapi.yml index 3cbb376..789a16b 100644 --- a/specs/account-management.openapi.yml +++ b/specs/account-management.openapi.yml @@ -673,45 +673,28 @@ paths: schema: type: array items: - type: object - properties: - id: - type: integer - name: - type: string - type: - type: string - access_level: - type: integer - resources: - type: array - items: - type: object - properties: - id: - type: integer - name: - type: string - type: - type: string - access_level: - type: integer - resources: - type: array - items: - nullable: true - type: object + $ref: '#/components/schemas/PermissionResourceNode' example: - - id: 4001 - name: My First Project - type: project - access_level: 1 + - id: 1774100 + name: Account + type: account + access_level: 100 resources: - - id: 3816 - name: My First Inbox - type: inbox + - id: 1774100 + name: Templates + type: email_template_permission_scope access_level: 100 resources: [] + - id: 2550469 + name: My Project + type: project + access_level: 100 + resources: + - id: 4117907 + name: My Inbox + type: inbox + access_level: 100 + resources: [] '401': $ref: '#/components/responses/UNAUTHENTICATED' '403': @@ -1061,7 +1044,13 @@ paths: '401': $ref: '#/components/responses/UNAUTHENTICATED' '403': - $ref: '#/components/responses/PERMISSION_DENIED' + description: Insufficient organization permissions or wrong organization. + content: + application/json: + schema: + $ref: '#/components/schemas/PermissionsDeniedResponse' + example: + errors: Access forbidden post: operationId: createOrganizationSubAccount summary: Create organization sub account @@ -1117,7 +1106,13 @@ paths: '401': $ref: '#/components/responses/UNAUTHENTICATED' '403': - $ref: '#/components/responses/PERMISSION_DENIED' + description: Insufficient organization permissions or wrong organization. + content: + application/json: + schema: + $ref: '#/components/schemas/PermissionsDeniedResponse' + example: + errors: Access forbidden '422': description: Unprocessable entity - validation errors. content: @@ -1141,6 +1136,25 @@ components: type: string example: Development Team Account description: The name of the sub account + PermissionResourceNode: + title: Permission resource node + description: | + Nested resource tree for permission management. `type` values include `account`, `project`, `inbox`, + `sending_domain`, `email_template_permission_scope`, `email_campaign_permission_scope`, and others. + type: object + properties: + id: + type: integer + name: + type: string + type: + type: string + access_level: + type: integer + resources: + type: array + items: + $ref: '#/components/schemas/PermissionResourceNode' AccountAccess: title: AccountAccess description: Assigns resource-specific permissions to a specifier. @@ -1220,6 +1234,7 @@ components: enum: - account - billing + - organization - project - inbox - sending_domain @@ -1259,14 +1274,20 @@ components: type: string description: Error message example: Not Found + example: + error: Not Found PermissionsDeniedResponse: title: PermissionsDeniedResponse type: object properties: errors: type: string - description: Error message - example: Access forbidden + description: | + Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account) + and `Access forbidden` (e.g. insufficient rights on an organization). + example: Account access forbidden + example: + errors: Account access forbidden UnauthenticatedResponse: title: UnauthenticatedResponse type: object @@ -1275,6 +1296,8 @@ components: type: string description: Error message example: Incorrect API token + example: + error: Incorrect API token ErrorResponse: title: ErrorResponse type: object @@ -1459,18 +1482,24 @@ components: application/json: schema: $ref: '#/components/schemas/UnauthenticatedResponse' + example: + error: Incorrect API token PERMISSION_DENIED: description: Returns forbidden error message. Check your permissions. content: application/json: schema: $ref: '#/components/schemas/PermissionsDeniedResponse' + example: + errors: Account access forbidden NOT_FOUND: description: Returns not found error message content: application/json: schema: $ref: '#/components/schemas/NotFoundResponse' + example: + error: Not Found UNPROCESSABLE_ENTITY: description: Validation error or other business rule violation content: diff --git a/specs/contacts.openapi.yml b/specs/contacts.openapi.yml index f0c9e85..a71907e 100644 --- a/specs/contacts.openapi.yml +++ b/specs/contacts.openapi.yml @@ -643,7 +643,14 @@ paths: '403': $ref: '#/components/responses/PERMISSION_DENIED' '404': - $ref: '#/components/responses/NOT_FOUND' + description: |- + No contact for the given identifier. The JSON body uses an `errors` string (not the `error` key used by some other 404 responses). + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + errors: Contact(s) not found '429': $ref: '#/components/responses/LIMIT_EXCEEDED' '500': @@ -1787,15 +1794,15 @@ paths: example: - id: 6730 name: First name - type: text + data_type: text merge_tag: first_name - id: 6731 name: Birthdate - type: date + data_type: date merge_tag: birthdate - id: 6732 name: Cats count - type: integer + data_type: integer merge_tag: cats_count '401': $ref: '#/components/responses/UNAUTHENTICATED' @@ -2735,6 +2742,8 @@ components: type: string description: Error message example: Unexpected error + example: + errors: Unexpected error NotFoundResponse: title: NotFoundResponse type: object @@ -2743,14 +2752,20 @@ components: type: string description: Error message example: Not Found + example: + error: Not Found PermissionsDeniedResponse: title: PermissionsDeniedResponse type: object properties: errors: type: string - description: Error message - example: Access forbidden + description: | + Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account) + and `Access forbidden` when the token lacks rights for the operation. + example: Account access forbidden + example: + errors: Account access forbidden RateLimitExceededResponse: title: RateLimitExceededResponse type: object @@ -2759,6 +2774,8 @@ components: type: string description: Error message example: Rate limit exceeded + example: + errors: Rate limit exceeded UnauthenticatedResponse: title: UnauthenticatedResponse type: object @@ -2767,6 +2784,8 @@ components: type: string description: Error message example: Incorrect API token + example: + error: Incorrect API token UnprocessableEntity: title: UnprocessableEntity type: object @@ -2782,30 +2801,40 @@ components: application/json: schema: $ref: '#/components/schemas/UnauthenticatedResponse' + example: + error: Incorrect API token LIMIT_EXCEEDED: description: Rate limit exceeded for the current account. content: application/json: schema: $ref: '#/components/schemas/RateLimitExceededResponse' + example: + errors: Rate limit exceeded PERMISSION_DENIED: description: Returns forbidden error message. Check your permissions. content: application/json: schema: $ref: '#/components/schemas/PermissionsDeniedResponse' + example: + errors: Account access forbidden INTERNAL_ERROR: description: Internal error. Retry later or contact support. content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' + example: + errors: Unexpected error NOT_FOUND: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/NotFoundResponse' + example: + error: Not Found parameters: account_id: description: Unique account ID diff --git a/specs/email-sending-bulk.openapi.yml b/specs/email-sending-bulk.openapi.yml index 2b77b5f..2cc0b73 100644 --- a/specs/email-sending-bulk.openapi.yml +++ b/specs/email-sending-bulk.openapi.yml @@ -15,7 +15,9 @@ info: url: 'https://mailtrap.io/wp-content/uploads/2021/04/mailtrap-logo.svg' servers: - - description: Bulk Stream + - description: | + Bulk Stream. Use a normal HTTP client `User-Agent` (as typical browsers and `curl` do); bare + requests without one may be blocked by edge protection. url: 'https://bulk.api.mailtrap.io' security: @@ -741,6 +743,9 @@ components: SendEmailErrorResponse: type: object + description: | + Error responses from the sending API use `success: false` and an `errors` array of strings + (unlike account APIs on `mailtrap.io`, which use `error` or a single `errors` string). properties: success: type: boolean @@ -750,6 +755,10 @@ components: items: type: string example: Invalid sender email address + example: + success: false + errors: + - "'from' address is invalid" BatchEmail: title: Batch Email Request @@ -832,7 +841,10 @@ components: example: success: false errors: - - "'from' address is invalid" + - "'from' is required" + - "'to', 'cc' or 'bcc' address is required" + - "'subject' is required" + - must specify either text or html body Unauthorized: description: Unauthorized. Check your API credentials. @@ -843,7 +855,7 @@ components: example: success: false errors: - - "Unauthorized" + - Unauthorized Forbidden: description: Forbidden. Verify domain or check permissions. @@ -851,6 +863,10 @@ components: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Forbidden InternalError: description: Internal server error. Retry later or contact support. @@ -858,3 +874,7 @@ components: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Internal server error diff --git a/specs/email-sending-transactional.openapi.yml b/specs/email-sending-transactional.openapi.yml index ff4b047..b554bf3 100644 --- a/specs/email-sending-transactional.openapi.yml +++ b/specs/email-sending-transactional.openapi.yml @@ -15,7 +15,9 @@ info: url: 'https://mailtrap.io/wp-content/uploads/2021/04/mailtrap-logo.svg' servers: - - description: Transactional Stream + - description: | + Transactional Stream. Use a normal HTTP client `User-Agent` (as typical browsers and `curl` do); bare + requests without one may be blocked by edge protection. url: 'https://send.api.mailtrap.io' security: @@ -710,6 +712,9 @@ components: SendEmailErrorResponse: type: object + description: | + Error responses from the sending API use `success: false` and an `errors` array of strings + (unlike account APIs on `mailtrap.io`, which use `error` or a single `errors` string). properties: success: type: boolean @@ -719,6 +724,10 @@ components: items: type: string example: Invalid sender email address + example: + success: false + errors: + - "'from' address is invalid" BatchEmail: title: Batch Email Request @@ -801,7 +810,10 @@ components: example: success: false errors: - - "'from' address is invalid" + - "'from' is required" + - "'to', 'cc' or 'bcc' address is required" + - "'subject' is required" + - must specify either text or html body Unauthorized: description: Unauthorized. Check your API credentials. @@ -812,7 +824,7 @@ components: example: success: false errors: - - "Unauthorized" + - Unauthorized Forbidden: description: Forbidden. Verify domain or check permissions. @@ -820,6 +832,10 @@ components: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Forbidden InternalError: description: Internal server error. Retry later or contact support. @@ -827,3 +843,7 @@ components: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Internal server error diff --git a/specs/email-sending.openapi.yml b/specs/email-sending.openapi.yml index 3a30568..38a56da 100644 --- a/specs/email-sending.openapi.yml +++ b/specs/email-sending.openapi.yml @@ -15,7 +15,9 @@ info: url: 'https://mailtrap.io/wp-content/uploads/2021/04/mailtrap-logo.svg' servers: - - description: Mailtrap API + - description: | + Mailtrap account API (`mailtrap.io`) for sending domains, suppressions, stats, and email logs. + Error JSON matches other account endpoints (`error` or string `errors`), not the `send.api` / `bulk.api` sending shape (`success` + `errors` array). url: 'https://mailtrap.io' security: @@ -2068,6 +2070,10 @@ components: type: array items: type: string + example: + errors: + base: + - "Validation failed: Domain name can't be blank, Tracking domain name is not a valid domain name" SendingStats: title: SendingStats @@ -2111,29 +2117,26 @@ components: BadRequest: title: BadRequestResponse + description: | + Invalid parameters. Some endpoints return an empty body with HTTP 400; when present, a message may use an `error` field. type: object properties: - success: - type: boolean - example: false - errors: - type: array - items: - type: string - example: "Invalid request parameters" + error: + type: string + example: Bad Request + example: + error: Bad Request RateLimitExceededResponse: title: RateLimitExceededResponse type: object properties: - success: - type: boolean - example: false errors: - type: array - items: - type: string - example: "Rate limit exceeded" + type: string + description: Error message + example: Rate limit exceeded + example: + errors: Rate limit exceeded EmailLogsListResponse: type: object @@ -2876,51 +2879,67 @@ components: operator: equal value: transactional - ErrorResponse: + UnauthenticatedResponse: + title: UnauthenticatedResponse + type: object + properties: + error: + type: string + description: Error message + example: Incorrect API token + example: + error: Incorrect API token + + PermissionsDeniedResponse: + title: PermissionsDeniedResponse type: object properties: - success: - type: boolean - example: false errors: - type: array - items: - type: string - example: Invalid request + type: string + description: | + Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account). + example: Account access forbidden + example: + errors: Account access forbidden + + NotFoundResponse: + title: NotFoundResponse + type: object + properties: + error: + type: string + description: Error message + example: Not Found + example: + error: Not Found responses: Unauthorized: - description: Unauthorized. Check your API credentials. + description: Returns unauthorized error message. Check your credentials. content: application/json: schema: - $ref: '#/components/schemas/ErrorResponse' + $ref: '#/components/schemas/UnauthenticatedResponse' example: - success: false - errors: - - "Unauthorized" + error: Incorrect API token Forbidden: - description: Forbidden. Verify domain or check permissions. + description: Returns forbidden error message. Check your permissions. content: application/json: schema: - $ref: '#/components/schemas/ErrorResponse' + $ref: '#/components/schemas/PermissionsDeniedResponse' example: - success: false - errors: - - "Forbidden" + errors: Account access forbidden NotFound: description: Resource not found content: application/json: schema: - type: object - properties: - error: - type: string - example: Resource not found + $ref: '#/components/schemas/NotFoundResponse' + example: + error: Not Found UnprocessableEntity: description: Validation errors @@ -2928,6 +2947,10 @@ components: application/json: schema: $ref: '#/components/schemas/UnprocessableEntity' + example: + errors: + base: + - "Validation failed: Domain name can't be blank, Tracking domain name is not a valid domain name" BAD_REQUEST: description: Bad request - invalid parameters. @@ -2936,9 +2959,7 @@ components: schema: $ref: '#/components/schemas/BadRequest' example: - success: false - errors: - - "Invalid request parameters" + error: Bad Request LIMIT_EXCEEDED: description: Rate limit exceeded for the current account. @@ -2947,9 +2968,7 @@ components: schema: $ref: '#/components/schemas/RateLimitExceededResponse' example: - success: false - errors: - - "Rate limit exceeded" + errors: Rate limit exceeded SendingDomainResponse: description: Sending domain details diff --git a/specs/sandbox-sending.openapi.yml b/specs/sandbox-sending.openapi.yml index 97d65cc..2b95b33 100644 --- a/specs/sandbox-sending.openapi.yml +++ b/specs/sandbox-sending.openapi.yml @@ -14,7 +14,10 @@ security: - HeaderAuth: [] - BearerAuth: [] servers: - - description: Mailtrap Sandbox API + - description: | + Mailtrap Sandbox Send API. Error bodies use `success: false` and an `errors` array (same family as + `send.api` / `bulk.api`), not the `mailtrap.io` account shape (`error` / string `errors`). + Use a normal HTTP client `User-Agent` (e.g. `curl`); bare requests may be blocked by edge protection. url: 'https://sandbox.api.mailtrap.io' tags: - name: Test Emails @@ -205,24 +208,43 @@ paths: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - "'from' is required" + - "'to', 'cc' or 'bcc' address is required" + - "'subject' is required" + - must specify either text or html body '401': description: Unauthorized. Make sure you are sending correct credentials with the request before retrying. content: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Unauthorized '429': description: Billing plan limit exhausted or inbox rate limit exceeded (see the response for details). content: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Rate limit exceeded '500': description: Internal error. Mail was not delivered. Retry later or contact support. content: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Internal server error parameters: - $ref: '#/components/parameters/inbox_id' '/api/batch/{inbox_id}': @@ -456,18 +478,30 @@ paths: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - "empty field: 'requests'" '401': description: Unauthorized. Make sure you are sending correct credentials with the request before retrying. content: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Unauthorized '500': description: Internal error. Messages were not delivered. Retry later or contact support. content: application/json: schema: $ref: '#/components/schemas/SendEmailErrorResponse' + example: + success: false + errors: + - Internal server error parameters: - $ref: '#/components/parameters/inbox_id' components: @@ -900,14 +934,23 @@ components: minLength: 1 SendEmailErrorResponse: title: SendEmailErrorResponse + description: | + Error responses use `success: false` and an `errors` array of strings (same pattern as Transactional + and Bulk sending APIs). type: object properties: success: type: boolean + example: false errors: type: array items: type: string + example: "'from' address is invalid" + example: + success: false + errors: + - "'from' address is invalid" SentResponse: title: SentResponse type: object diff --git a/specs/sandbox.openapi.yml b/specs/sandbox.openapi.yml index 0175477..a6813ca 100644 --- a/specs/sandbox.openapi.yml +++ b/specs/sandbox.openapi.yml @@ -1951,9 +1951,7 @@ paths: content: application/json: schema: - oneOf: - - $ref: '#/components/schemas/InboxMessageWithoutBlacklistsReportInfo' - - $ref: '#/components/schemas/InboxMessageWithBlacklistsReportInfo' + $ref: '#/components/schemas/SandboxInboxMessage' example: id: 2323 inbox_id: 17002 @@ -1967,6 +1965,8 @@ paths: is_read: false created_at: '2022-07-01T19:29:59.295Z' updated_at: '2022-07-01T19:29:59.295Z' + template_id: 0 + template_variables: null html_body_size: 150 text_body_size: 100 human_size: 300 Bytes @@ -1975,12 +1975,18 @@ paths: raw_path: /api/accounts/16297/inboxes/17002/messages/2323/body.raw download_path: /api/accounts/16297/inboxes/17002/messages/2323/body.eml html_source_path: /api/accounts/16297/inboxes/17002/messages/2323/body.htmlsource - blacklists_report_info: false + blacklists_report_info: + result: success + domain: example.com + ip: 23.215.0.138 + report: [] smtp_information: ok: true data: mail_from_addr: john@mailtrap.io client_ip: 193.62.62.184 + rcpt_to_addrs: + - mary@mailtrap.io '401': $ref: '#/components/responses/UNAUTHENTICATED' '403': @@ -2579,62 +2585,7 @@ paths: schema: type: array items: - type: object - properties: - id: - type: integer - inbox_id: - type: integer - subject: - type: string - sent_at: - type: string - from_email: - type: string - from_name: - type: string - to_email: - type: string - to_name: - type: string - email_size: - type: integer - is_read: - type: boolean - created_at: - type: string - updated_at: - type: string - html_body_size: - type: integer - text_body_size: - type: integer - human_size: - type: string - html_path: - type: string - txt_path: - type: string - raw_path: - type: string - download_path: - type: string - html_source_path: - type: string - blacklists_report_info: - type: boolean - smtp_information: - type: object - properties: - ok: - type: boolean - data: - type: object - properties: - mail_from_addr: - type: string - client_ip: - type: string + $ref: '#/components/schemas/SandboxInboxMessage' example: - id: 92 inbox_id: 342 @@ -2648,6 +2599,8 @@ paths: is_read: false created_at: '2022-08-19T11:34:33.841Z' updated_at: '2022-08-19T11:34:33.841Z' + template_id: 0 + template_variables: null html_body_size: 150 text_body_size: 100 human_size: 300 Bytes @@ -2656,12 +2609,15 @@ paths: raw_path: /api/accounts/336/inboxes/342/messages/92/body.raw download_path: /api/accounts/336/inboxes/342/messages/92/body.eml html_source_path: /api/accounts/336/inboxes/342/messages/92/body.htmlsource - blacklists_report_info: false + blacklists_report_info: + result: pending smtp_information: ok: true data: mail_from_addr: per667son25@feeney.biz client_ip: 75.180.183.201 + rcpt_to_addrs: + - per688son26@donnelly.info '401': $ref: '#/components/responses/UNAUTHENTICATED' '403': @@ -4571,9 +4527,12 @@ paths: - $ref: '#/components/parameters/attachment_id' components: schemas: - InboxMessageWithoutBlacklistsReportInfo: - title: Message without blacklists report + SandboxInboxMessage: + title: Sandbox inbox message type: object + description: | + Email message captured in a Sandbox inbox. Body URLs are often under `/api/testing_message_parts/...` rather than nested under `/api/accounts/.../messages/...`. + `blacklists_report_info` may contain only `result` or the full report. `template_variables` is set when the message was sent from a template. properties: id: type: integer @@ -4599,64 +4558,12 @@ components: type: string updated_at: type: string - html_body_size: - type: integer - text_body_size: + template_id: type: integer - human_size: - type: string - html_path: - type: string - txt_path: - type: string - raw_path: - type: string - download_path: - type: string - html_source_path: - type: string - blacklists_report_info: - type: boolean - smtp_information: + template_variables: type: object - properties: - ok: - type: boolean - data: - type: object - properties: - mail_from_addr: - type: string - client_ip: - type: string - InboxMessageWithBlacklistsReportInfo: - title: Message with blacklists report - type: object - properties: - id: - type: integer - inbox_id: - type: integer - subject: - type: string - sent_at: - type: string - from_email: - type: string - from_name: - type: string - to_email: - type: string - to_name: - type: string - email_size: - type: integer - is_read: - type: boolean - created_at: - type: string - updated_at: - type: string + nullable: true + additionalProperties: true html_body_size: type: integer text_body_size: @@ -4709,6 +4616,10 @@ components: type: string client_ip: type: string + rcpt_to_addrs: + type: array + items: + type: string Project: title: Testing Project type: object @@ -4760,6 +4671,8 @@ components: type: string description: Error message example: Not Found + example: + error: Not Found PermissionsDeniedResponse: title: PermissionsDeniedResponse type: object @@ -4767,7 +4680,9 @@ components: errors: type: string description: Error message - example: Access forbidden + example: Account access forbidden + example: + errors: Account access forbidden TestingInbox: title: Testing Inbox type: object @@ -4883,6 +4798,8 @@ components: type: string description: Error message example: Incorrect API token + example: + error: Incorrect API token examples: Projects: summary: List of projects @@ -5072,18 +4989,24 @@ components: application/json: schema: $ref: '#/components/schemas/UnauthenticatedResponse' + example: + error: Incorrect API token PERMISSION_DENIED: description: Returns forbidden error message. Check your permissions. content: application/json: schema: $ref: '#/components/schemas/PermissionsDeniedResponse' + example: + errors: Account access forbidden NOT_FOUND: description: Returns not found error message content: application/json: schema: $ref: '#/components/schemas/NotFoundResponse' + example: + error: Not Found ProjectsResponse: description: |- Lists project attributes and inboxes of this project with their attributes. diff --git a/specs/templates.openapi.yml b/specs/templates.openapi.yml index 407e264..972b749 100644 --- a/specs/templates.openapi.yml +++ b/specs/templates.openapi.yml @@ -553,7 +553,8 @@ components: description: Account ID schema: type: integer - example: 1 + format: int64 + example: 3229 email_template_id: name: email_template_id @@ -562,7 +563,8 @@ components: description: Email template ID schema: type: integer - example: 1 + format: int64 + example: 60927 schemas: UnprocessableEntity: @@ -574,6 +576,46 @@ components: type: array items: type: string + example: + errors: + category: + - can't be blank + subject: + - can't be blank + + UnauthenticatedResponse: + title: UnauthenticatedResponse + type: object + properties: + error: + type: string + description: Error message + example: Incorrect API token + example: + error: Incorrect API token + + PermissionsDeniedResponse: + title: PermissionsDeniedResponse + type: object + properties: + errors: + type: string + description: | + Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account). + example: Account access forbidden + example: + errors: Account access forbidden + + NotFoundResponse: + title: NotFoundResponse + type: object + properties: + error: + type: string + description: Error message + example: Not Found + example: + error: Not Found EmailTemplateRequest: title: EmailTemplateRequest @@ -643,7 +685,7 @@ components: format: date-time example: id: 26730 - uuid: 018dd5e3-f6d2-7c00-8f9b-e5c3f2d8a132 + uuid: '018dd5e3-f6d2-7c00-8f9b-e5c3f2d8a132' name: My Email Template subject: Promotional Email category: Promotional @@ -652,51 +694,33 @@ components: created_at: '2021-01-01T00:00:00Z' updated_at: '2021-01-01T00:00:00Z' - ErrorResponse: - type: object - properties: - success: - type: boolean - example: false - errors: - type: array - items: - type: string - example: Invalid request - responses: Unauthorized: - description: Unauthorized. Check your API credentials. + description: Returns unauthorized error message. Check your credentials. content: application/json: schema: - $ref: '#/components/schemas/ErrorResponse' + $ref: '#/components/schemas/UnauthenticatedResponse' example: - success: false - errors: - - "Unauthorized" + error: Incorrect API token Forbidden: - description: Forbidden. Verify domain or check permissions. + description: Returns forbidden error message. Check your permissions. content: application/json: schema: - $ref: '#/components/schemas/ErrorResponse' + $ref: '#/components/schemas/PermissionsDeniedResponse' example: - success: false - errors: - - "Forbidden" + errors: Account access forbidden NotFound: description: Resource not found content: application/json: schema: - type: object - properties: - error: - type: string - example: Resource not found + $ref: '#/components/schemas/NotFoundResponse' + example: + error: Not Found UnprocessableEntity: description: Validation errors @@ -704,3 +728,9 @@ components: application/json: schema: $ref: '#/components/schemas/UnprocessableEntity' + example: + errors: + category: + - can't be blank + subject: + - can't be blank From 86b3906fee4aab6221fa19ad64d219972cf4bf37 Mon Sep 17 00:00:00 2001 From: Ganna Bielanova Date: Wed, 6 May 2026 12:02:43 +0300 Subject: [PATCH 2/5] MT-21122: updated examples for 422 --- specs/account-management.openapi.yml | 8 ++++++++ specs/contacts.openapi.yml | 8 ++++++++ specs/email-sending.openapi.yml | 15 +++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/specs/account-management.openapi.yml b/specs/account-management.openapi.yml index 789a16b..302e7ff 100644 --- a/specs/account-management.openapi.yml +++ b/specs/account-management.openapi.yml @@ -1313,6 +1313,14 @@ components: errors: type: object description: Validation errors per attribute. Entire record errors are under `base` key. + additionalProperties: + type: array + items: + type: string + example: + errors: + base: + - No permissions selected. Please choose at least one. ApiToken: type: object properties: diff --git a/specs/contacts.openapi.yml b/specs/contacts.openapi.yml index a71907e..b7f34c2 100644 --- a/specs/contacts.openapi.yml +++ b/specs/contacts.openapi.yml @@ -2793,6 +2793,14 @@ components: errors: type: object description: Validation errors per attribute. Entire record errors are under `base` key. + additionalProperties: + type: array + items: + type: string + example: + errors: + email: + - can't be blank examples: {} responses: UNAUTHENTICATED: diff --git a/specs/email-sending.openapi.yml b/specs/email-sending.openapi.yml index 38a56da..a4fe03d 100644 --- a/specs/email-sending.openapi.yml +++ b/specs/email-sending.openapi.yml @@ -2063,6 +2063,9 @@ components: UnprocessableEntity: type: object + description: |- + Validation errors per field. Keys are attribute names; values are arrays of human-readable messages. + Some endpoints may also return a `base` key with general validation errors. properties: errors: type: object @@ -2072,6 +2075,12 @@ components: type: string example: errors: + email: + - can't be blank + domain: + - can't be blank + sending_stream: + - 'is invalid. Allowed values: transactional, bulk.' base: - "Validation failed: Domain name can't be blank, Tracking domain name is not a valid domain name" @@ -2949,6 +2958,12 @@ components: $ref: '#/components/schemas/UnprocessableEntity' example: errors: + email: + - can't be blank + domain: + - can't be blank + sending_stream: + - 'is invalid. Allowed values: transactional, bulk.' base: - "Validation failed: Domain name can't be blank, Tracking domain name is not a valid domain name" From a2ed7bcc678cd134888f7adcc27e59957a2b491b Mon Sep 17 00:00:00 2001 From: DagonWat Date: Thu, 7 May 2026 11:25:17 +0200 Subject: [PATCH 3/5] Fix some wording on email sending openapi --- specs/email-sending.openapi.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/specs/email-sending.openapi.yml b/specs/email-sending.openapi.yml index a4fe03d..b22acba 100644 --- a/specs/email-sending.openapi.yml +++ b/specs/email-sending.openapi.yml @@ -1310,7 +1310,13 @@ paths: stats: $ref: '#/components/schemas/SendingStats' '400': - $ref: '#/components/responses/BAD_REQUEST' + description: Bad request - invalid parameters. + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + example: + error: "Missing required parameter: start_date" '401': $ref: '#/components/responses/Unauthorized' '403': @@ -2905,8 +2911,7 @@ components: properties: errors: type: string - description: | - Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account). + description: Error message example: Account access forbidden example: errors: Account access forbidden From bedc607ddfbc3501eb8eea2bb97e82b821bb3bd2 Mon Sep 17 00:00:00 2001 From: DagonWat Date: Thu, 7 May 2026 16:35:25 +0200 Subject: [PATCH 4/5] Fix openapi endpoints errors --- specs/contacts.openapi.yml | 16 ---------------- specs/sandbox.openapi.yml | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/specs/contacts.openapi.yml b/specs/contacts.openapi.yml index b7f34c2..0afe486 100644 --- a/specs/contacts.openapi.yml +++ b/specs/contacts.openapi.yml @@ -247,14 +247,6 @@ paths: $ref: '#/components/responses/UNAUTHENTICATED' '403': $ref: '#/components/responses/PERMISSION_DENIED' - '409': - description: A Contact with the same email is already being created. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - example: - errors: Contact exists '422': description: Returns validation errors. content: @@ -540,14 +532,6 @@ paths: $ref: '#/components/responses/UNAUTHENTICATED' '403': $ref: '#/components/responses/PERMISSION_DENIED' - '409': - description: A Contact with the same email is already being created. - content: - application/json: - schema: - $ref: '#/components/schemas/ErrorResponse' - example: - errors: Contact exists '422': description: Returns validation errors. content: diff --git a/specs/sandbox.openapi.yml b/specs/sandbox.openapi.yml index a6813ca..fdf0d85 100644 --- a/specs/sandbox.openapi.yml +++ b/specs/sandbox.openapi.yml @@ -1998,7 +1998,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden '404': $ref: '#/components/responses/NOT_FOUND' x-codeSamples: @@ -2629,7 +2629,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden operationId: getInboxEmailMessage x-codeSamples: - lang: shell @@ -2811,7 +2811,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden '404': $ref: '#/components/responses/NOT_FOUND' x-codeSamples: @@ -3009,7 +3009,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden '404': $ref: '#/components/responses/NOT_FOUND' x-codeSamples: @@ -3192,7 +3192,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden '404': $ref: '#/components/responses/NOT_FOUND' x-codeSamples: @@ -3317,7 +3317,7 @@ paths: text/plain: schema: type: string - example: '{:errors=>"Inbox is not active or you have insufficient permissions"}' + example: '{:errors=>"Account access forbidden"}' '404': $ref: '#/components/responses/NOT_FOUND' '409': @@ -3493,7 +3493,7 @@ paths: text/plain: schema: type: string - example: '{:errors=>"Inbox is not active or you have insufficient permissions"}' + example: '{:errors=>"Account access forbidden"}' '404': $ref: '#/components/responses/NOT_FOUND' '409': @@ -3648,7 +3648,7 @@ paths: text/plain: schema: type: string - example: '{:errors=>"Inbox is not active or you have insufficient permissions"}' + example: '{:errors=>"Account access forbidden"}' '404': $ref: '#/components/responses/NOT_FOUND' '409': @@ -3797,7 +3797,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden '404': $ref: '#/components/responses/NOT_FOUND' '409': @@ -3975,7 +3975,7 @@ paths: text/plain: schema: type: string - example: '{:errors=>"Inbox is not active or you have insufficient permissions"}' + example: '{:errors=>"Account access forbidden"}' '404': $ref: '#/components/responses/NOT_FOUND' '409': @@ -4274,7 +4274,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden '404': $ref: '#/components/responses/NOT_FOUND' operationId: getInboxMessageAttachments @@ -4430,7 +4430,7 @@ paths: properties: errors: type: string - example: Inbox is not active or you have insufficient permissions + example: Account access forbidden '404': $ref: '#/components/responses/NOT_FOUND' operationId: getInboxMessageAttachment From 8f908357155f87728a26ba860a1e2d286457e740 Mon Sep 17 00:00:00 2001 From: DagonWat Date: Fri, 8 May 2026 12:40:21 +0200 Subject: [PATCH 5/5] Remove unnecessary comments --- specs/account-management.openapi.yml | 3 --- specs/contacts.openapi.yml | 3 --- specs/templates.openapi.yml | 2 -- 3 files changed, 8 deletions(-) diff --git a/specs/account-management.openapi.yml b/specs/account-management.openapi.yml index 302e7ff..b037fa9 100644 --- a/specs/account-management.openapi.yml +++ b/specs/account-management.openapi.yml @@ -1282,9 +1282,6 @@ components: properties: errors: type: string - description: | - Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account) - and `Access forbidden` (e.g. insufficient rights on an organization). example: Account access forbidden example: errors: Account access forbidden diff --git a/specs/contacts.openapi.yml b/specs/contacts.openapi.yml index 0afe486..d9ba219 100644 --- a/specs/contacts.openapi.yml +++ b/specs/contacts.openapi.yml @@ -2744,9 +2744,6 @@ components: properties: errors: type: string - description: | - Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account) - and `Access forbidden` when the token lacks rights for the operation. example: Account access forbidden example: errors: Account access forbidden diff --git a/specs/templates.openapi.yml b/specs/templates.openapi.yml index 972b749..9e1c98c 100644 --- a/specs/templates.openapi.yml +++ b/specs/templates.openapi.yml @@ -600,8 +600,6 @@ components: properties: errors: type: string - description: | - Human-readable reason. Common values include `Account access forbidden` (e.g. wrong account). example: Account access forbidden example: errors: Account access forbidden