openapi: 3.0.3 info: title: happyDeliver API description: Email Deliverability Testing Platform API version: 0.1.0 contact: name: happyDomain team url: https://github.com/happyDomain/happydeliver email: contact+api@happydomain.org license: name: GNU Affero General Public License v3.0 or later url: https://spdx.org/licenses/AGPL-3.0-or-later.html servers: - url: http://localhost:8080/api description: Local development server - url: https://api.example.com/api description: Production server tags: - name: tests description: Test management operations - name: reports description: Report retrieval operations - name: health description: Service health and status paths: /test: post: tags: - tests summary: Create a new deliverability test description: Generates a unique test email address for sending test emails. No database record is created until an email is received. operationId: createTest responses: '201': description: Test email address generated successfully content: application/json: schema: $ref: '#/components/schemas/TestResponse' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /test/upload: post: tags: - tests summary: Analyze an uploaded EML file description: > Analyzes a raw email message (.eml) provided by the user instead of one delivered to this instance's MTA. Authentication results are read from the Authentication-Results headers already present in the file, using an auto-detected authserv-id. The resulting report is stored like any other and is immediately available. operationId: uploadEml requestBody: required: true content: multipart/form-data: schema: type: object required: - file properties: file: type: string format: binary description: The raw email message to analyze responses: '201': description: File analyzed successfully content: application/json: schema: $ref: '#/components/schemas/EmlUploadResponse' '400': description: Missing, oversized or unparsable file content: application/json: schema: $ref: '#/components/schemas/Error' '403': description: EML upload is disabled on this instance content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /test/{id}: get: tags: - tests summary: Get test status description: Check if a report exists for the given test ID (base32-encoded). Returns pending if no report exists, analyzed if a report is available. operationId: getTest parameters: - name: id in: path required: true schema: type: string pattern: '^[a-z0-9-]+$' description: Base32-encoded test ID (with hyphens) responses: '200': description: Test status retrieved successfully content: application/json: schema: $ref: '#/components/schemas/Test' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /tests: get: tags: - tests summary: List all tests description: Returns a paginated list of test summaries with scores and grades. Can be disabled via server configuration. operationId: listTests parameters: - name: offset in: query schema: type: integer minimum: 0 default: 0 description: Number of items to skip - name: limit in: query schema: type: integer minimum: 1 maximum: 100 default: 20 description: Maximum number of items to return responses: '200': description: List of test summaries content: application/json: schema: $ref: '#/components/schemas/TestListResponse' '403': description: Test listing is disabled content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /report/{id}: get: tags: - reports summary: Get detailed report description: Retrieve comprehensive deliverability analysis report operationId: getReport parameters: - name: id in: path required: true schema: type: string pattern: '^[a-z0-9-]+$' description: Base32-encoded test ID (with hyphens) responses: '200': description: Report retrieved successfully content: application/json: schema: $ref: '#/components/schemas/Report' '404': description: Report not found content: application/json: schema: $ref: '#/components/schemas/Error' /report/{id}/raw.eml: get: tags: - reports summary: Get raw annotated email description: Retrieve the original email with headers added by filters operationId: getRawEmail parameters: - name: id in: path required: true schema: type: string pattern: '^[a-z0-9-]+$' description: Base32-encoded test ID (with hyphens) responses: '200': description: Raw email retrieved successfully content: text/plain: schema: type: string '404': description: Email not found content: application/json: schema: $ref: '#/components/schemas/Error' /report/{id}/reanalyze: post: tags: - reports summary: Reanalyze email and regenerate report description: Re-run the analysis on the stored raw email to regenerate the report with the latest analyzer version. This is useful after analyzer improvements or bug fixes. operationId: reanalyzeReport parameters: - name: id in: path required: true schema: type: string pattern: '^[a-z0-9-]+$' description: Base32-encoded test ID (with hyphens) responses: '200': description: Report regenerated successfully content: application/json: schema: $ref: '#/components/schemas/Report' '404': description: Email not found content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error during reanalysis content: application/json: schema: $ref: '#/components/schemas/Error' /domain: post: tags: - tests summary: Test a domain's email configuration description: Analyzes DNS records (MX, SPF, DMARC, BIMI) for a domain without requiring an actual email to be sent. Returns results immediately. operationId: testDomain requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/DomainTestRequest' responses: '200': description: Domain test completed successfully content: application/json: schema: $ref: '#/components/schemas/DomainTestResponse' '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /bimi: post: tags: - tests summary: Check a domain's BIMI record description: Looks up the BIMI Assertion Record of a domain and validates it together with the assets it points at (logo and Verified Mark Certificate), without requiring an actual email to be sent. The DMARC record of the same domain is reported alongside, since BIMI display depends on it. Returns results immediately. operationId: checkBimi requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BIMICheckRequest' responses: '200': description: BIMI check completed successfully content: application/json: schema: $ref: '#/components/schemas/BIMICheckResponse' '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /blacklist: post: tags: - tests summary: Check an IP address against DNS blacklists description: Tests a single IP address (IPv4 or IPv6) against configured DNS-based blacklists (RBLs) without requiring an actual email to be sent. Returns results immediately. operationId: checkBlacklist requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BlacklistCheckRequest' responses: '200': description: Blacklist check completed successfully content: application/json: schema: $ref: '#/components/schemas/BlacklistCheckResponse' '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Error' '500': description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' /status: get: tags: - health summary: Service health check description: Get service health status and component versions operationId: getStatus responses: '200': description: Service status content: application/json: schema: $ref: '#/components/schemas/Status' components: schemas: Test: $ref: './schemas.yaml#/components/schemas/Test' TestResponse: $ref: './schemas.yaml#/components/schemas/TestResponse' EmlUploadResponse: $ref: './schemas.yaml#/components/schemas/EmlUploadResponse' Report: $ref: './schemas.yaml#/components/schemas/Report' ScoreSummary: $ref: './schemas.yaml#/components/schemas/ScoreSummary' ContentAnalysis: $ref: './schemas.yaml#/components/schemas/ContentAnalysis' Issue: $ref: './schemas.yaml#/components/schemas/Issue' LinkCheck: $ref: './schemas.yaml#/components/schemas/LinkCheck' ImageCheck: $ref: './schemas.yaml#/components/schemas/ImageCheck' HeaderAnalysis: $ref: './schemas.yaml#/components/schemas/HeaderAnalysis' HeaderCheck: $ref: './schemas.yaml#/components/schemas/HeaderCheck' ReceivedHop: $ref: './schemas.yaml#/components/schemas/ReceivedHop' DKIMDomainInfo: $ref: './schemas.yaml#/components/schemas/DKIMDomainInfo' DomainAlignment: $ref: './schemas.yaml#/components/schemas/DomainAlignment' HeaderIssue: $ref: './schemas.yaml#/components/schemas/HeaderIssue' AuthenticationResults: $ref: './schemas.yaml#/components/schemas/AuthenticationResults' AuthResult: $ref: './schemas.yaml#/components/schemas/AuthResult' ARCResult: $ref: './schemas.yaml#/components/schemas/ARCResult' IPRevResult: $ref: './schemas.yaml#/components/schemas/IPRevResult' SpamAssassinResult: $ref: './schemas.yaml#/components/schemas/SpamAssassinResult' SpamTestDetail: $ref: './schemas.yaml#/components/schemas/SpamTestDetail' RspamdResult: $ref: './schemas.yaml#/components/schemas/RspamdResult' DNSResults: $ref: './schemas.yaml#/components/schemas/DNSResults' MXRecord: $ref: './schemas.yaml#/components/schemas/MXRecord' SPFRecord: $ref: './schemas.yaml#/components/schemas/SPFRecord' DKIMRecord: $ref: './schemas.yaml#/components/schemas/DKIMRecord' DMARCRecord: $ref: './schemas.yaml#/components/schemas/DMARCRecord' BIMIRecord: $ref: './schemas.yaml#/components/schemas/BIMIRecord' BIMICheck: $ref: './schemas.yaml#/components/schemas/BIMICheck' VMCInfo: $ref: './schemas.yaml#/components/schemas/VMCInfo' BlacklistCheck: $ref: './schemas.yaml#/components/schemas/BlacklistCheck' Status: $ref: './schemas.yaml#/components/schemas/Status' Error: $ref: './schemas.yaml#/components/schemas/Error' DomainTestRequest: $ref: './schemas.yaml#/components/schemas/DomainTestRequest' DomainTestResponse: $ref: './schemas.yaml#/components/schemas/DomainTestResponse' BIMICheckRequest: $ref: './schemas.yaml#/components/schemas/BIMICheckRequest' BIMICheckResponse: $ref: './schemas.yaml#/components/schemas/BIMICheckResponse' BlacklistCheckRequest: $ref: './schemas.yaml#/components/schemas/BlacklistCheckRequest' BlacklistCheckResponse: $ref: './schemas.yaml#/components/schemas/BlacklistCheckResponse' TestSummary: $ref: './schemas.yaml#/components/schemas/TestSummary' TestListResponse: $ref: './schemas.yaml#/components/schemas/TestListResponse'