{"openapi":"3.1.0","info":{"title":"Asphaleia Systems Webhook API","version":"1.0.0","summary":"Webhook receiver for inbound email events.","description":"This specification covers the only production JSON API currently exposed by Asphaleia Systems. The endpoint is an integration callback for Resend, not a general-purpose client API. New integrations should use /api/v1/mail/inbound. The legacy /api/mail/inbound URL remains supported for existing hooks. Breaking API changes use a new major URL version; a retired version will be announced with Deprecation and Sunset headers and at least 12 months notice. No fixed request quota is currently published or enforced.","contact":{"name":"Asphaleia Systems","email":"hello@asphaleiasystems.com","url":"https://www.asphaleiasystems.com/en/contact"}},"servers":[{"url":"https://www.asphaleiasystems.com"}],"paths":{"/api":{"get":{"operationId":"discoverAsphaleiaApi","summary":"Discover API endpoints and error conventions","description":"Returns the documented endpoints, OpenAPI URL and JSON error format. Other methods return a structured 405 error.","responses":{"200":{"description":"API discovery document.","content":{"application/json":{"schema":{"type":"object","required":["name","documentation","openapi","errorFormat","endpoints"],"properties":{"name":{"type":"string"},"documentation":{"type":"string","format":"uri"},"openapi":{"type":"string","format":"uri"},"errorFormat":{"type":"object","properties":{"contentType":{"type":"string"},"fields":{"type":"array","items":{"type":"string"}}}},"endpoints":{"type":"array","items":{"type":"object","required":["operationId","method","path"],"properties":{"operationId":{"type":"string"},"method":{"type":"string"},"path":{"type":"string"},"deprecated":{"type":"boolean"}}}}}}}}},"405":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}}}}},"/api/v1/mail/inbound":{"post":{"operationId":"receiveInboundEmailWebhookV1","summary":"Receive a version 1 inbound email event","description":"Version 1 of the Resend email.received webhook. Verifies the Svix signature over the exact request bytes and files the message in the private admin inbox. Configure RESEND_WEBHOOK_SECRET and the mail database before use. Requests over 5 MB are rejected. Resend may retry 5xx responses.","security":[{"svixWebhookSignature":[]}],"parameters":[{"in":"header","name":"svix-id","required":true,"description":"Unique webhook message identifier supplied by Resend.","schema":{"type":"string"}},{"in":"header","name":"svix-timestamp","required":true,"description":"Webhook timestamp supplied by Resend.","schema":{"type":"string"}},{"in":"header","name":"svix-signature","required":true,"description":"Svix signature supplied by Resend.","schema":{"type":"string"}}],"requestBody":{"required":true,"description":"Original JSON body from a Resend email.received event. Verification uses the exact raw bytes.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Webhook event accepted.","content":{"application/json":{"schema":{"type":"object","required":["ok","result"],"properties":{"ok":{"type":"boolean","const":true},"result":{"type":"string","enum":["stored","duplicate","ignored"],"description":"Whether the message was stored, already present, or unsupported."}}},"example":{"ok":true,"result":"stored"}}}},"400":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"401":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"413":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"500":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"503":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}}}}},"/api/mail/inbound":{"post":{"operationId":"receiveInboundEmailWebhook","summary":"Receive an inbound email event","description":"Accepts a Resend email.received webhook, verifies its Svix signature against the exact request bytes, and files the message in the private admin inbox. Configure RESEND_WEBHOOK_SECRET and the mail database before use. Requests over 5 MB are rejected. Resend may retry 5xx responses.","security":[{"svixWebhookSignature":[]}],"parameters":[{"in":"header","name":"svix-id","required":true,"description":"Unique webhook message identifier supplied by Resend.","schema":{"type":"string"}},{"in":"header","name":"svix-timestamp","required":true,"description":"Webhook timestamp supplied by Resend.","schema":{"type":"string"}},{"in":"header","name":"svix-signature","required":true,"description":"Svix signature supplied by Resend.","schema":{"type":"string"}}],"requestBody":{"required":true,"description":"The original JSON body from a Resend email.received event. Signature verification is performed over the exact raw bytes.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"200":{"description":"Webhook event accepted.","content":{"application/json":{"schema":{"type":"object","required":["ok","result"],"properties":{"ok":{"type":"boolean","const":true,"description":"Confirms the event was processed."},"result":{"type":"string","enum":["stored","duplicate","ignored"],"description":"Whether the message was stored, was already present, or did not match a supported event."}}},"example":{"ok":true,"result":"stored"}}}},"400":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"401":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"413":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"500":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}},"503":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}}}}},"/api/avatar/{id}":{"get":{"operationId":"getPublicMailAvatar","summary":"Retrieve a public mailbox avatar","description":"Returns the JPEG profile image identified by its random, unguessable 128-bit id. Replacing or removing a photo invalidates its id. This endpoint does not enumerate avatars.","parameters":[{"in":"path","name":"id","required":true,"description":"Random 128-bit public photo identifier.","schema":{"type":"string","pattern":"^[a-f0-9]{32}$"}}],"responses":{"200":{"description":"JPEG avatar image.","content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Structured API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"error":{"code":"INVALID_SIGNATURE","message":"The webhook signature could not be verified.","resolution":"Check the Resend signing secret and svix signature headers."}}}}}}}}},"components":{"securitySchemes":{"svixWebhookSignature":{"type":"apiKey","in":"header","name":"svix-signature","description":"Resend's Svix signature is verified together with svix-id and svix-timestamp using the configured webhook secret."}},"schemas":{"ErrorEnvelope":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","resolution"],"properties":{"code":{"type":"string","description":"Stable machine-readable error code."},"message":{"type":"string","description":"Human-readable explanation."},"resolution":{"type":"string","description":"Suggested corrective action."}}}}}}}}