All checks were successful
continuous-integration/drone/push Build is passing
576 lines
16 KiB
YAML
576 lines
16 KiB
YAML
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/{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'
|
|
|
|
/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:
|
|
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'
|
|
|
|
/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:
|
|
type: object
|
|
required:
|
|
- id
|
|
- email
|
|
- status
|
|
properties:
|
|
id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Unique test identifier (base32-encoded with hyphens)
|
|
example: "krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a"
|
|
email:
|
|
type: string
|
|
format: email
|
|
description: Unique test email address
|
|
example: "test-krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a@example.com"
|
|
status:
|
|
type: string
|
|
enum: [pending, analyzed]
|
|
description: Current test status (pending = no report yet, analyzed = report available)
|
|
example: "analyzed"
|
|
|
|
TestResponse:
|
|
type: object
|
|
required:
|
|
- id
|
|
- email
|
|
- status
|
|
properties:
|
|
id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Unique test identifier (base32-encoded with hyphens)
|
|
example: "krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a"
|
|
email:
|
|
type: string
|
|
format: email
|
|
example: "test-krfwg4z-amrqw4z-zmorsw2-djmfzgk-3a@example.com"
|
|
status:
|
|
type: string
|
|
enum: [pending]
|
|
example: "pending"
|
|
message:
|
|
type: string
|
|
example: "Send your test email to the address above"
|
|
|
|
Report:
|
|
type: object
|
|
required:
|
|
- id
|
|
- test_id
|
|
- score
|
|
- grade
|
|
- checks
|
|
- created_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Report identifier (base32-encoded with hyphens)
|
|
test_id:
|
|
type: string
|
|
pattern: '^[a-z0-9-]+$'
|
|
description: Associated test ID (base32-encoded with hyphens)
|
|
score:
|
|
type: number
|
|
format: float
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Overall deliverability score as percentage (0-100)
|
|
example: 85
|
|
grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
summary:
|
|
$ref: '#/components/schemas/ScoreSummary'
|
|
checks:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Check'
|
|
authentication:
|
|
$ref: '#/components/schemas/AuthenticationResults'
|
|
spamassassin:
|
|
$ref: '#/components/schemas/SpamAssassinResult'
|
|
dns_records:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/DNSRecord'
|
|
blacklists:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/BlacklistCheck'
|
|
raw_headers:
|
|
type: string
|
|
description: Raw email headers
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
ScoreSummary:
|
|
type: object
|
|
required:
|
|
- authentication_score
|
|
- spam_score
|
|
- blacklist_score
|
|
- content_score
|
|
- header_score
|
|
properties:
|
|
authentication_score:
|
|
type: number
|
|
format: float
|
|
minimum: 0
|
|
maximum: 100
|
|
description: SPF/DKIM/DMARC score (in percentage)
|
|
example: 28
|
|
spam_score:
|
|
type: number
|
|
format: float
|
|
minimum: 0
|
|
maximum: 100
|
|
description: SpamAssassin score (in percentage)
|
|
example: 15
|
|
blacklist_score:
|
|
type: number
|
|
format: float
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Blacklist check score (in percentage)
|
|
example: 20
|
|
content_score:
|
|
type: number
|
|
format: float
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Content quality score (in percentage)
|
|
example: 18
|
|
header_score:
|
|
type: number
|
|
format: float
|
|
minimum: 0
|
|
maximum: 100
|
|
description: Header quality score (in percentage)
|
|
example: 9
|
|
|
|
Check:
|
|
type: object
|
|
required:
|
|
- category
|
|
- name
|
|
- status
|
|
- score
|
|
- grade
|
|
- message
|
|
properties:
|
|
category:
|
|
type: string
|
|
enum: [authentication, dns, content, blacklist, headers, spam]
|
|
description: Check category
|
|
example: "authentication"
|
|
name:
|
|
type: string
|
|
description: Check name
|
|
example: "DKIM Signature"
|
|
status:
|
|
type: string
|
|
enum: [pass, fail, warn, info, error]
|
|
description: Check result status
|
|
example: "pass"
|
|
score:
|
|
type: number
|
|
format: float
|
|
description: Points contributed to total score
|
|
example: 10
|
|
grade:
|
|
type: string
|
|
enum: [A+, A, B, C, D, E, F]
|
|
description: Letter grade representation of the score (A+ is best, F is worst)
|
|
example: "A"
|
|
message:
|
|
type: string
|
|
description: Human-readable result message
|
|
example: "DKIM signature is valid"
|
|
details:
|
|
type: string
|
|
description: Additional details (may be JSON)
|
|
severity:
|
|
type: string
|
|
enum: [critical, high, medium, low, info]
|
|
description: Issue severity
|
|
example: "info"
|
|
advice:
|
|
type: string
|
|
description: Remediation advice
|
|
example: "Your DKIM configuration is correct"
|
|
|
|
AuthenticationResults:
|
|
type: object
|
|
properties:
|
|
spf:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
dkim:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
dmarc:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
bimi:
|
|
$ref: '#/components/schemas/AuthResult'
|
|
arc:
|
|
$ref: '#/components/schemas/ARCResult'
|
|
|
|
AuthResult:
|
|
type: object
|
|
required:
|
|
- result
|
|
properties:
|
|
result:
|
|
type: string
|
|
enum: [pass, fail, none, neutral, softfail, temperror, permerror]
|
|
description: Authentication result
|
|
example: "pass"
|
|
domain:
|
|
type: string
|
|
description: Domain being authenticated
|
|
example: "example.com"
|
|
selector:
|
|
type: string
|
|
description: DKIM selector (for DKIM only)
|
|
example: "default"
|
|
details:
|
|
type: string
|
|
description: Additional details about the result
|
|
|
|
ARCResult:
|
|
type: object
|
|
required:
|
|
- result
|
|
properties:
|
|
result:
|
|
type: string
|
|
enum: [pass, fail, none]
|
|
description: Overall ARC chain validation result
|
|
example: "pass"
|
|
chain_valid:
|
|
type: boolean
|
|
description: Whether the ARC chain signatures are valid
|
|
example: true
|
|
chain_length:
|
|
type: integer
|
|
description: Number of ARC sets in the chain
|
|
example: 2
|
|
details:
|
|
type: string
|
|
description: Additional details about ARC validation
|
|
example: "ARC chain valid with 2 intermediaries"
|
|
|
|
SpamAssassinResult:
|
|
type: object
|
|
required:
|
|
- score
|
|
- required_score
|
|
- is_spam
|
|
properties:
|
|
score:
|
|
type: number
|
|
format: float
|
|
description: SpamAssassin spam score
|
|
example: 2.3
|
|
required_score:
|
|
type: number
|
|
format: float
|
|
description: Threshold for spam classification
|
|
example: 5.0
|
|
is_spam:
|
|
type: boolean
|
|
description: Whether message is classified as spam
|
|
example: false
|
|
tests:
|
|
type: array
|
|
items:
|
|
type: string
|
|
description: List of triggered SpamAssassin tests
|
|
example: ["BAYES_00", "DKIM_SIGNED"]
|
|
report:
|
|
type: string
|
|
description: Full SpamAssassin report
|
|
|
|
DNSRecord:
|
|
type: object
|
|
required:
|
|
- domain
|
|
- record_type
|
|
- status
|
|
properties:
|
|
domain:
|
|
type: string
|
|
description: Domain name
|
|
example: "example.com"
|
|
record_type:
|
|
type: string
|
|
enum: [MX, SPF, DKIM, DMARC, BIMI]
|
|
description: DNS record type
|
|
example: "SPF"
|
|
status:
|
|
type: string
|
|
enum: [found, missing, invalid]
|
|
description: Record status
|
|
example: "found"
|
|
value:
|
|
type: string
|
|
description: Record value
|
|
example: "v=spf1 include:_spf.example.com ~all"
|
|
|
|
BlacklistCheck:
|
|
type: object
|
|
required:
|
|
- ip
|
|
- rbl
|
|
- listed
|
|
properties:
|
|
ip:
|
|
type: string
|
|
description: IP address checked
|
|
example: "192.0.2.1"
|
|
rbl:
|
|
type: string
|
|
description: RBL/DNSBL name
|
|
example: "zen.spamhaus.org"
|
|
listed:
|
|
type: boolean
|
|
description: Whether IP is listed
|
|
example: false
|
|
response:
|
|
type: string
|
|
description: RBL response code or message
|
|
example: "127.0.0.2"
|
|
|
|
Status:
|
|
type: object
|
|
required:
|
|
- status
|
|
- version
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum: [healthy, degraded, unhealthy]
|
|
description: Overall service status
|
|
example: "healthy"
|
|
version:
|
|
type: string
|
|
description: Service version
|
|
example: "0.1.0-dev"
|
|
components:
|
|
type: object
|
|
properties:
|
|
database:
|
|
type: string
|
|
enum: [up, down]
|
|
example: "up"
|
|
mta:
|
|
type: string
|
|
enum: [up, down]
|
|
example: "up"
|
|
uptime:
|
|
type: integer
|
|
description: Service uptime in seconds
|
|
example: 3600
|
|
|
|
Error:
|
|
type: object
|
|
required:
|
|
- error
|
|
- message
|
|
properties:
|
|
error:
|
|
type: string
|
|
description: Error code
|
|
example: "not_found"
|
|
message:
|
|
type: string
|
|
description: Human-readable error message
|
|
example: "Test not found"
|
|
details:
|
|
type: string
|
|
description: Additional error details
|