{"openapi":"3.0.0","paths":{"/health":{"get":{"operationId":"HealthController_check","parameters":[],"responses":{"200":{"description":""}},"tags":["Health"]}},"/health/ready":{"get":{"operationId":"HealthController_checkReady","parameters":[],"responses":{"200":{"description":""}},"tags":["Health"]}},"/health/db":{"get":{"operationId":"HealthController_checkDb","parameters":[],"responses":{"200":{"description":""}},"tags":["Health"]}},"/health/redis":{"get":{"operationId":"HealthController_checkRedis","parameters":[],"responses":{"200":{"description":""}},"tags":["Health"]}},"/health/queues":{"get":{"operationId":"HealthController_checkQueues","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"bearer":[]}],"tags":["Health"]}},"/auth/registration-status":{"get":{"operationId":"AuthController_registrationStatus","parameters":[],"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/register":{"post":{"operationId":"AuthController_register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["Auth"]}},"/auth/login":{"post":{"operationId":"AuthController_login","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["Auth"]}},"/auth/login/verify-2fa":{"post":{"operationId":"AuthController_verify2fa","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Verify2faDto"}}}},"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/forgot-password":{"post":{"operationId":"AuthController_forgotPassword","parameters":[{"name":"accept-language","required":true,"in":"header","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordDto"}}}},"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/reset-password":{"post":{"operationId":"AuthController_resetPassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordDto"}}}},"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/refresh":{"post":{"operationId":"AuthController_refresh","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshDto"}}}},"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/logout":{"post":{"operationId":"AuthController_logout","parameters":[],"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/change-password":{"post":{"operationId":"AuthController_changePassword","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordDto"}}}},"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/me":{"get":{"operationId":"AuthController_me","parameters":[],"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/verify-email":{"post":{"operationId":"AuthController_verifyEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmailDto"}}}},"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/resend-verification-email":{"post":{"operationId":"AuthController_resendVerificationEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResendVerificationDto"}}}},"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/resend-verification":{"post":{"operationId":"AuthController_resendVerification","parameters":[],"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/logout-all":{"post":{"operationId":"AuthController_logoutAll","parameters":[],"responses":{"200":{"description":""}},"tags":["Auth"]}},"/auth/2fa/status":{"get":{"operationId":"TwoFactorController_status","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["2FA"]}},"/auth/2fa/enable":{"post":{"operationId":"TwoFactorController_enable","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["2FA"]}},"/auth/2fa/verify":{"post":{"operationId":"TwoFactorController_verify","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Enable2faDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["2FA"]}},"/auth/2fa/disable":{"post":{"operationId":"TwoFactorController_disable","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Enable2faDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["2FA"]}},"/tenants":{"post":{"operationId":"TenantsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTenantDto"}}}},"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]},"get":{"operationId":"TenantsController_findAll","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}":{"get":{"operationId":"TenantsController_findOne","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Tenants"]},"patch":{"operationId":"TenantsController_update","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTenantDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]},"delete":{"operationId":"TenantsController_delete","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/members":{"post":{"operationId":"TenantsController_inviteMember","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteMemberDto"}}}},"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]},"get":{"operationId":"TenantsController_listMembers","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/members/{targetAdminId}/role":{"patch":{"operationId":"TenantsController_updateMemberRole","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetAdminId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemberRoleDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/members/{targetAdminId}":{"delete":{"operationId":"TenantsController_removeMember","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}},{"name":"targetAdminId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/api-keys":{"post":{"operationId":"TenantsController_createApiKey","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyDto"}}}},"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]},"get":{"operationId":"TenantsController_listApiKeys","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/api-keys/{apiKeyId}/rotate":{"post":{"operationId":"TenantsController_rotateApiKey","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}},{"name":"apiKeyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/api-keys/{apiKeyId}":{"delete":{"operationId":"TenantsController_revokeApiKey","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}},{"name":"apiKeyId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/resume-sending":{"post":{"operationId":"TenantsController_resumeSending","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/block":{"post":{"operationId":"TenantsController_block","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/tenants/{tenantId}/unblock":{"post":{"operationId":"TenantsController_unblock","parameters":[{"name":"tenantId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Tenants"]}},"/emails/send":{"post":{"operationId":"EmailsController_send","parameters":[{"name":"sync","required":true,"in":"query","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"summary":"POST /emails/send\n\nEncola el envío para procesamiento asíncrono vía BullMQ.\nUsa ?sync=true para envío síncrono directo (debug/testing).","tags":["Emails"]}},"/emails/send-template":{"post":{"operationId":"EmailsController_sendTemplate","parameters":[{"name":"sync","required":true,"in":"query","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendTemplateDto"}}}},"responses":{"202":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"summary":"POST /emails/send-template\n\nEnvía usando una plantilla publicada (por `slug`) renderizada con `data`.\nAsync por defecto (BullMQ); ?sync=true para envío directo (pruebas).","tags":["Emails"]}},"/emails/logs":{"get":{"operationId":"EmailsController_getLogs","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Emails"]}},"/emails/logs/{id}":{"get":{"operationId":"EmailsController_getLogDetail","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"summary":"GET /emails/logs/:id\n\nDetalle de un log de envío, incluyendo `bodyHtml`/`bodyText` (#98) para\nprevisualización. 404 si no existe o pertenece a otro tenant.","tags":["Emails"]}},"/emails/logs/{id}/resend":{"post":{"operationId":"EmailsController_resendLog","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"summary":"POST /emails/logs/:id/resend\n\nReenvía cualquier log (no solo fallidos, #98) reutilizando el pipeline de\n`send()`: hereda suppression check, quota, tracking, tag de baja y audit.\nNO reutiliza el idempotencyKey original — es un envío nuevo.","tags":["Emails"]}},"/emails/batch":{"post":{"operationId":"EmailsController_sendBatch","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendBatchDto"}}}},"responses":{"202":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"summary":"POST /emails/batch\n\nEnvía a múltiples destinatarios (máx 100) en una sola llamada.\nCada destinatario recibe el mismo template con variables personalizadas.\nLos emails suprimidos se rechazan automáticamente.","tags":["Emails"]}},"/webhooks/endpoints":{"get":{"operationId":"WebhooksController_listEndpoints","parameters":[],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Webhooks"]},"post":{"operationId":"WebhooksController_createEndpoint","parameters":[],"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Webhooks"]}},"/webhooks/endpoints/{id}":{"delete":{"operationId":"WebhooksController_deleteEndpoint","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Webhooks"]}},"/webhooks/endpoints/{id}/toggle":{"patch":{"operationId":"WebhooksController_toggleEndpoint","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Webhooks"]}},"/webhooks/endpoints/{id}/deliveries":{"get":{"operationId":"WebhooksController_getDeliveries","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"limit","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Webhooks"]}},"/webhooks/ses":{"post":{"operationId":"SesWebhookController_handle","parameters":[],"responses":{"200":{"description":""}},"tags":["Webhooks (SES)"]}},"/contacts":{"put":{"operationId":"ContactsController_upsert","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertContactDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]},"get":{"operationId":"ContactsController_list","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":500,"default":50,"type":"number"}},{"name":"locale","required":false,"in":"query","schema":{"type":"string"}},{"name":"optIn","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"updatedSince","required":false,"in":"query","schema":{"type":"string"}},{"name":"cursor","required":false,"in":"query","schema":{"type":"string"}},{"name":"projectId","required":false,"in":"query","schema":{"type":"string"}},{"name":"tag","required":false,"in":"query","schema":{"maxLength":50,"pattern":"CONTACT_TAG_PATTERN","type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contacts/bulk":{"post":{"operationId":"ContactsController_bulkUpsert","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkUpsertContactsDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contacts/{idOrExternalId}":{"get":{"operationId":"ContactsController_getOne","parameters":[{"name":"idOrExternalId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contacts/{id}":{"patch":{"operationId":"ContactsController_patch","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchContactDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contacts/{idOrExternalId}/tags":{"post":{"operationId":"ContactsController_addTags","parameters":[{"name":"idOrExternalId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddTagsDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contacts/{idOrExternalId}/tags/{tag}":{"delete":{"operationId":"ContactsController_removeTag","parameters":[{"name":"idOrExternalId","required":true,"in":"path","schema":{"type":"string"}},{"name":"tag","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contacts/{externalId}":{"delete":{"operationId":"ContactsController_erase","parameters":[{"name":"externalId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contact-tags":{"get":{"operationId":"ContactTagsController_list","parameters":[],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]},"post":{"operationId":"ContactTagsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateContactTagDto"}}}},"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/contact-tags/{name}":{"patch":{"operationId":"ContactTagsController_update","parameters":[{"name":"name","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateContactTagDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]},"delete":{"operationId":"ContactTagsController_remove","parameters":[{"name":"name","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Contacts"]}},"/projects":{"get":{"operationId":"ProjectsController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Projects"]},"post":{"operationId":"ProjectsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateProjectDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Projects"]}},"/projects/{id}":{"get":{"operationId":"ProjectsController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Projects"]},"patch":{"operationId":"ProjectsController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateProjectDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Projects"]},"delete":{"operationId":"ProjectsController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Projects"]}},"/projects/{id}/verify-smtp":{"post":{"operationId":"ProjectsController_verifySmtp","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Projects"]}},"/domains":{"post":{"operationId":"DeliverabilityController_register","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDomainDto"}}}},"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Deliverability"]},"get":{"operationId":"DeliverabilityController_list","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Deliverability"]}},"/domains/{id}/dns":{"get":{"operationId":"DeliverabilityController_getDns","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Deliverability"]}},"/domains/{id}/verify":{"post":{"operationId":"DeliverabilityController_verify","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Deliverability"]}},"/domains/{id}/diagnose":{"get":{"operationId":"DeliverabilityController_diagnose","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"summary":"Diagnóstico completo del DNS del dominio: qué está mal y qué registro dejar\npublicado para arreglarlo. No escribe estado — para eso está `POST :id/verify`.","tags":["Deliverability"]}},"/domains/{id}":{"delete":{"operationId":"DeliverabilityController_delete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Deliverability"]}},"/platform/settings":{"get":{"operationId":"PlatformController_get","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Platform"]},"patch":{"operationId":"PlatformController_update","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdatePlatformSettingsDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Platform"]}},"/templates/render-react-email":{"post":{"operationId":"TemplatesController_renderReactEmail","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenderReactEmailDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"summary":"Render React Email JSX to HTML (preview, no persist)","tags":["Templates"]}},"/templates":{"post":{"operationId":"TemplatesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTemplateDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]},"get":{"operationId":"TemplatesController_list","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"search","required":false,"in":"query","schema":{"type":"string"}},{"name":"projectId","required":false,"in":"query","schema":{"type":"string"}},{"name":"status","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}},{"name":"editorMode","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"summary":"GET /templates — lista de plantillas del tenant.\n\nAccesible por JWT (dashboard) o por API key con scope `templates:read`\n(p. ej. el MCP server / agentes, para descubrir slugs publicados). El\n`ScopesGuard` solo exige el scope a requests con API key; los JWT pasan.","tags":["Templates"]}},"/templates/{id}":{"get":{"operationId":"TemplatesController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]},"patch":{"operationId":"TemplatesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]},"delete":{"operationId":"TemplatesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/duplicate":{"post":{"operationId":"TemplatesController_duplicate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/versions":{"post":{"operationId":"TemplatesController_createVersion","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/versions/{versionId}":{"get":{"operationId":"TemplatesController_getVersion","parameters":[{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]},"patch":{"operationId":"TemplatesController_updateVersion","parameters":[{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateVersionDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]},"delete":{"operationId":"TemplatesController_deleteVersion","parameters":[{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/versions/{versionId}/publish":{"post":{"operationId":"TemplatesController_publishVersion","parameters":[{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/versions/{versionId}/unpublish":{"post":{"operationId":"TemplatesController_unpublishVersion","parameters":[{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/versions/{versionId}/preview":{"post":{"operationId":"TemplatesController_previewVersion","parameters":[{"name":"versionId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/tags":{"get":{"operationId":"TemplatesController_listTags","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]},"post":{"operationId":"TemplatesController_createTag","parameters":[],"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/tags/{tagId}":{"delete":{"operationId":"TemplatesController_deleteTag","parameters":[{"name":"tagId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/tags":{"get":{"operationId":"TemplatesController_getTemplateTags","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/templates/{id}/tags/{tagId}":{"post":{"operationId":"TemplatesController_attachTag","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"tagId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Templates"]},"delete":{"operationId":"TemplatesController_detachTag","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"tagId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Templates"]}},"/suppressions":{"get":{"operationId":"SuppressionsController_list","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"email","required":false,"in":"query","schema":{"format":"email","type":"string"}},{"name":"reason","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Suppressions"]},"post":{"operationId":"SuppressionsController_add","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSuppressionDto"}}}},"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Suppressions"]},"delete":{"operationId":"SuppressionsController_removeByEmail","parameters":[{"name":"email","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Suppressions"]}},"/suppressions/{id}":{"delete":{"operationId":"SuppressionsController_removeById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Suppressions"]}},"/campaigns":{"post":{"operationId":"CampaignsController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCampaignDto"}}}},"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]},"get":{"operationId":"CampaignsController_list","parameters":[{"name":"status","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]}},"/campaigns/{id}/locale-coverage":{"get":{"operationId":"CampaignsController_getLocaleCoverage","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]}},"/campaigns/{id}":{"get":{"operationId":"CampaignsController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]},"patch":{"operationId":"CampaignsController_patch","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchCampaignDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]}},"/campaigns/{id}/test":{"post":{"operationId":"CampaignsController_testSend","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestCampaignDto"}}}},"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]}},"/campaigns/{id}/schedule":{"post":{"operationId":"CampaignsController_schedule","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleCampaignDto"}}}},"responses":{"202":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]}},"/campaigns/{id}/send":{"post":{"operationId":"CampaignsController_sendNow","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"202":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]}},"/campaigns/{id}/cancel":{"post":{"operationId":"CampaignsController_cancel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Campaigns"]}},"/ab-tests":{"get":{"operationId":"AbTestingController_list","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}}},"security":[{"JWT":[]}],"tags":["A/B Testing"]},"post":{"operationId":"AbTestingController_create","parameters":[],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["A/B Testing"]}},"/ab-tests/{id}/start":{"post":{"operationId":"AbTestingController_start","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["A/B Testing"]}},"/ab-tests/{id}/complete":{"post":{"operationId":"AbTestingController_complete","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["A/B Testing"]}},"/scheduled-emails":{"post":{"operationId":"ScheduledEmailsController_schedule","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleEmailDto"}}}},"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Scheduled Emails"]},"get":{"operationId":"ScheduledEmailsController_list","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Scheduled Emails"]}},"/scheduled-emails/{id}":{"delete":{"operationId":"ScheduledEmailsController_cancel","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Scheduled Emails"]}},"/sequences":{"post":{"operationId":"SequencesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSequenceDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]},"get":{"operationId":"SequencesController_list","parameters":[{"name":"status","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/sequences/events":{"post":{"operationId":"SequencesController_enrollByEvent","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollByEventDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"summary":"Dispara el trigger API_EVENT: inscribe `contactId` en todas las secuencias ACTIVE\ncuyo `triggerConfig.eventName` coincide. Ruta estática antes de las `:id/...`.\nDevuelve `{ matched, enrolled }` (200: puede coincidir con 0 secuencias).","tags":["Sequences"]}},"/sequences/{id}":{"get":{"operationId":"SequencesController_getById","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]},"patch":{"operationId":"SequencesController_patch","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSequenceDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]},"delete":{"operationId":"SequencesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/sequences/{id}/activate":{"post":{"operationId":"SequencesController_activate","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/sequences/{id}/pause":{"post":{"operationId":"SequencesController_pause","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/sequences/{id}/steps":{"post":{"operationId":"SequencesController_createStep","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSequenceStepDto"}}}},"responses":{"201":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/sequences/{id}/steps/{stepId}":{"patch":{"operationId":"SequencesController_patchStep","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"stepId","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchSequenceStepDto"}}}},"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]},"delete":{"operationId":"SequencesController_removeStep","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"stepId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/sequences/{id}/enroll":{"post":{"operationId":"SequencesController_enroll","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EnrollContactDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/sequences/{id}/enrollments":{"get":{"operationId":"SequencesController_listEnrollments","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}},{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}},{"name":"status","required":false,"in":"query","schema":{"$ref":"#/components/schemas/Object"}}],"responses":{"200":{"description":""}},"security":[{"API Key":[]},{"JWT":[]}],"tags":["Sequences"]}},"/u/{token}":{"get":{"operationId":"UnsubscribeController_showConfirm","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Unsubscribe"]},"post":{"operationId":"UnsubscribeController_confirm","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Unsubscribe"]}},"/track/o/{logId}":{"get":{"operationId":"TrackingController_trackOpen","parameters":[{"name":"logId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"GET /track/o/:logId — Open tracking pixel\nDevuelve un GIF transparente 1x1 después de registrar el open.","tags":["Tracking"]}},"/track/c/{logId}":{"get":{"operationId":"TrackingController_trackClick","parameters":[{"name":"logId","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"summary":"GET /track/c/:logId?url=...&sig=... — Click tracking\n\nRegistra el click y redirige a la URL original SOLO si la firma coincide con la\nque pusimos al reescribir el enlace (ADR-040). Sin firma válida el endpoint sería\nun open-redirect (`?url=https://phishing`): redirigimos a un destino seguro.","tags":["Tracking"]}},"/v1/agents/capabilities":{"get":{"operationId":"AgentsController_getCapabilities","parameters":[],"responses":{"200":{"description":""}},"tags":["Agents"]}},"/agents.md":{"get":{"operationId":"AgentsDocsController_redirectAgentsGuide","parameters":[],"responses":{"200":{"description":""}},"tags":["Agents"]}},"/llms.txt":{"get":{"operationId":"AgentsDocsController_redirectLlmsTxt","parameters":[],"responses":{"200":{"description":""}},"tags":["Agents"]}},"/memo/memos":{"post":{"operationId":"MemoIntakeController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMemoDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]},{"API Key":[]}],"tags":["Memo"]},"get":{"operationId":"MemoInboxController_list","parameters":[{"name":"siteId","required":false,"in":"query","schema":{"maxLength":64,"type":"string"}},{"name":"unread","required":false,"in":"query","schema":{"type":"boolean"}},{"name":"status","required":false,"in":"query","schema":{"enum":["OPEN","RESOLVED","PENDING"],"type":"string"}},{"name":"cursor","required":false,"in":"query","schema":{"maxLength":64,"type":"string"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":30,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]}},"/memo/sites":{"get":{"operationId":"MemoSitesController_list","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]},"post":{"operationId":"MemoSitesController_create","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMemoSiteDto"}}}},"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"summary":"Devuelve el sitio con `key` en claro: es la única vez que se ve.","tags":["Memo"]}},"/memo/sites/{id}":{"patch":{"operationId":"MemoSitesController_update","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMemoSiteDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]},"delete":{"operationId":"MemoSitesController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]}},"/memo/sites/{id}/rotate-key":{"post":{"operationId":"MemoSitesController_rotateKey","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"summary":"Nueva clave del servidor del sitio (la anterior deja de valer). Se ve una vez.","tags":["Memo"]}},"/memo/memos/{id}/screenshot":{"get":{"operationId":"MemoInboxController_screenshot","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]}},"/memo/memos/{id}":{"get":{"operationId":"MemoInboxController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Memo"]},"delete":{"operationId":"MemoInboxController_remove","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]}},"/memo/memos/{id}/read":{"patch":{"operationId":"MemoInboxController_setRead","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetMemoReadDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]}},"/memo/memos/{id}/status":{"patch":{"operationId":"MemoInboxController_setStatus","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetMemoStatusDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]}},"/memo/memos/{id}/replies":{"post":{"operationId":"MemoInboxController_reply","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplyMemoDto"}}}},"responses":{"201":{"description":""}},"security":[{"JWT":[]}],"tags":["Memo"]}},"/memo/chat/{token}":{"get":{"operationId":"MemoChatController_view","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["MemoChat"]},"post":{"operationId":"MemoChatController_post","parameters":[{"name":"token","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostMemoChatDto"}}}},"responses":{"201":{"description":""}},"tags":["MemoChat"]}},"/ai/generate":{"post":{"operationId":"AiController_generate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["AI"]}},"/ai/generate-template":{"post":{"operationId":"AiController_generateTemplate","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateTemplateDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["AI"]}},"/ai/improve":{"post":{"operationId":"AiController_improve","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImproveTemplateDto"}}}},"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["AI"]}},"/ai/balance":{"get":{"operationId":"AiController_getBalance","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["AI"]}},"/ai/usage":{"get":{"operationId":"AiController_getUsage","parameters":[{"name":"page","required":false,"in":"query","schema":{"minimum":1,"default":1,"type":"number"}},{"name":"limit","required":false,"in":"query","schema":{"minimum":1,"maximum":100,"default":20,"type":"number"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["AI"]}},"/ai/prompts":{"get":{"operationId":"AiPromptsController_list","parameters":[],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["AI Prompts"]}},"/ai/prompts/{key}":{"get":{"operationId":"AiPromptsController_get","parameters":[{"name":"key","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["AI Prompts"]},"put":{"operationId":"AiPromptsController_upsert","parameters":[{"name":"key","required":true,"in":"path","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAiPromptDto"}}}},"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["AI Prompts"]}},"/billing/plans":{"get":{"operationId":"BillingController_getPlans","parameters":[],"responses":{"200":{"description":""}},"tags":["Billing"]}},"/billing/checkout":{"post":{"operationId":"BillingController_createCheckout","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCheckoutDto"}}}},"responses":{"200":{"description":""}},"tags":["Billing"]}},"/billing/token-packs":{"get":{"operationId":"BillingController_getTokenPacks","parameters":[],"responses":{"200":{"description":""}},"tags":["Billing"]}},"/billing/token-packs/checkout":{"post":{"operationId":"BillingController_createTokenPackCheckout","parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateTokenPackCheckoutDto"}}}},"responses":{"200":{"description":""}},"tags":["Billing"]}},"/billing/portal":{"post":{"operationId":"BillingController_createPortal","parameters":[],"responses":{"200":{"description":""}},"tags":["Billing"]}},"/billing/subscription":{"get":{"operationId":"BillingController_getSubscription","parameters":[],"responses":{"200":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"tags":["Billing"]}},"/billing/webhook":{"post":{"operationId":"BillingController_webhook","parameters":[{"name":"stripe-signature","required":true,"in":"header","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"tags":["Billing"]}},"/analytics/summary":{"get":{"operationId":"AnalyticsController_getSummary","parameters":[{"name":"days","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"summary":"GET /analytics/summary\nDevuelve KPIs agregados de los últimos 30 días para el tenant actual.","tags":["Analytics"]}},"/analytics/daily":{"get":{"operationId":"AnalyticsController_getDaily","parameters":[{"name":"days","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"summary":"GET /analytics/daily\nDevuelve conteo diario de envíos para gráfico de barras (últimos N días).","tags":["Analytics"]}},"/analytics/top-templates":{"get":{"operationId":"AnalyticsController_getTopTemplates","parameters":[{"name":"days","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"summary":"GET /analytics/top-templates\nTop 10 templates por cantidad de envíos.","tags":["Analytics"]}},"/library":{"get":{"operationId":"LibraryController_list","parameters":[{"name":"category","required":true,"in":"query","schema":{"type":"string"}},{"name":"search","required":true,"in":"query","schema":{"type":"string"}},{"name":"locale","required":true,"in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Library"]}},"/library/{id}/preview":{"get":{"operationId":"LibraryController_preview","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Library"]}},"/library/{id}":{"get":{"operationId":"LibraryController_get","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"200":{"description":""}},"security":[{"JWT":[]}],"tags":["Library"]}},"/library/{id}/clone":{"post":{"operationId":"LibraryController_clone","parameters":[{"name":"id","required":true,"in":"path","schema":{"type":"string"}}],"responses":{"201":{"description":"","content":{"application/json":{"schema":{"type":"object"}}}}},"security":[{"JWT":[]}],"tags":["Library"]}}},"info":{"title":"MailingCore API","description":"Developer-first email platform — REST API for transactional email, templates, contacts, campaigns and multi-tenant management.","version":"0.1.0","contact":{}},"tags":[],"servers":[{"url":"http://localhost:3010","description":"Local development"},{"url":"https://api.mailingcore.com","description":"Production"}],"components":{"securitySchemes":{"JWT":{"scheme":"bearer","bearerFormat":"JWT","type":"http"},"API Key":{"scheme":"bearer","bearerFormat":"JWT","type":"http","description":"Scoped API key — envía `Authorization: Bearer mc_live_...`"}},"schemas":{"RegisterDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"name":{"type":"string","minLength":2,"maxLength":100},"password":{"type":"string","minLength":8,"maxLength":128},"website":{"type":"string","description":"Honeypot: si viene relleno, el registro finge éxito y no crea nada.","maxLength":200}},"required":["email","name","password"]},"LoginDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"password":{"type":"string","minLength":8}},"required":["email","password"]},"Verify2faDto":{"type":"object","properties":{"code":{"type":"string","minLength":6,"maxLength":8},"challengeId":{"type":"string"}},"required":["code","challengeId"]},"ForgotPasswordDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"lang":{"type":"string","description":"Idioma preferido para el email de reset (`es` | `en` | `it`). Acepta variantes\nregionales (`es-ES`); se normaliza en el backend. Si falta, se usa la cabecera\nAccept-Language y, en último término, el fallback por defecto.","maxLength":35}},"required":["email"]},"ResetPasswordDto":{"type":"object","properties":{"token":{"type":"string"},"newPassword":{"type":"string","minLength":8,"maxLength":128}},"required":["token","newPassword"]},"RefreshDto":{"type":"object","properties":{"refreshToken":{"type":"string"}},"required":["refreshToken"]},"ChangePasswordDto":{"type":"object","properties":{"currentPassword":{"type":"string"},"newPassword":{"type":"string","minLength":8,"maxLength":128}},"required":["currentPassword","newPassword"]},"VerifyEmailDto":{"type":"object","properties":{"token":{"type":"string","minLength":1}},"required":["token"]},"ResendVerificationDto":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]},"Enable2faDto":{"type":"object","properties":{"code":{"type":"string","minLength":6,"maxLength":6}},"required":["code"]},"CreateTenantDto":{"type":"object","properties":{"name":{"type":"string","minLength":2},"slug":{"type":"string","minLength":2,"maxLength":63,"pattern":"/^[a-z0-9]+(?:-[a-z0-9]+)*$/"}},"required":["name","slug"]},"UpdateTenantDto":{"type":"object","properties":{"name":{"type":"string","minLength":2}}},"InviteMemberDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"role":{"type":"object","default":"VIEWER"}},"required":["email","role"]},"UpdateMemberRoleDto":{"type":"object","properties":{"role":{"type":"object"}},"required":["role"]},"CreateApiKeyDto":{"type":"object","properties":{"name":{"type":"string","maxLength":80},"description":{"type":"string","maxLength":500},"scopes":{"type":"array","items":{"type":"string"}},"environment":{"type":"object","default":"LIVE"},"expirationPreset":{"type":"object","default":"never"},"expirationCustomValue":{"type":"number","minimum":1},"expirationCustomUnit":{"type":"object"}},"required":["name","scopes"]},"AttachmentDto":{"type":"object","properties":{"filename":{"type":"string","minLength":1,"maxLength":255},"content":{"type":"string","description":"Contenido en base64. El `@Transform` elimina espacios/saltos por si el cliente\nenvía base64 troceado en líneas (PEM-style); así `@IsBase64` valida el compacto.","format":"base64"},"contentType":{"type":"string","maxLength":255},"contentId":{"type":"string","description":"Content-ID opcional (ADR-047). Con él, el adjunto viaja inline dentro de\n`multipart/related` y el HTML lo referencia con `<img src=\"cid:...\">`. Solo\nletras, dígitos, `.`, `_` y `-` (1-64): el valor acaba en la cabecera `Content-ID`.","pattern":"CONTENT_ID_RE"}},"required":["filename","content"]},"SendEmailDto":{"type":"object","properties":{"to":{"type":"string","format":"email"},"subject":{"type":"string","maxLength":998},"htmlBody":{"type":"string"},"html":{"type":"string","description":"Alias de `htmlBody` (repo anterior). Se mapea a htmlBody en el servicio."},"textBody":{"type":"string"},"text":{"type":"string","description":"Alias de `textBody` (repo anterior). Se mapea a textBody en el servicio."},"fromEmail":{"type":"string"},"from":{"type":"string","description":"Alias de `fromEmail` (repo anterior). Se mapea a fromEmail en el servicio."},"fromName":{"type":"string"},"replyTo":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object"},"headers":{"type":"object","description":"Cabeceras adicionales del mensaje (`Precedence`, `Auto-Submitted`, `References`…).\n\nEl transporte ya las soportaba (`sendViaTransport` las propaga y `buildRawMimeMessage`\nlas escribe), pero no estaban expuestas en el DTO: con `forbidNonWhitelisted` activo,\ncualquier envío que las mandara se rechazaba con 400 antes de crear el EmailLog, sin\ndejar rastro en los logs de envío.\n\nLas cabeceras de baja (`List-Unsubscribe`, `List-Unsubscribe-Post`) las pone la\nplataforma y tienen prioridad: no se pueden pisar desde aquí."},"idempotencyKey":{"type":"string"},"templateVersionId":{"type":"string"},"projectId":{"type":"string"},"unsubscribeLang":{"type":"string"},"trackingDisabled":{"type":"boolean","description":"Opt-out de tracking para este envío (privacidad/GDPR): si es `true`, no se inyecta el\npíxel de apertura ni se reescriben los enlaces por el redirector de clics. La cabecera\n`List-Unsubscribe` y el enlace de baja se mantienen (requeridos). Por defecto: tracking on."},"attachments":{"description":"Adjuntos inline (base64), solo transporte — no se persisten a largo plazo (ADR-043).\nEl servicio limita tamaño por fichero y total antes de enviar (413 EMAIL_TOO_LARGE).","type":"array","items":{"$ref":"#/components/schemas/AttachmentDto"}}},"required":["to","subject"]},"SendTemplateDto":{"type":"object","properties":{"slug":{"type":"string"},"template":{"type":"string","description":"Alias de `slug` (repo anterior usaba `template`). Se mapea a slug."},"to":{"type":"string","format":"email"},"data":{"type":"object","description":"Variables de plantilla: `{ userName: \"Juan\", ... }`."},"fromEmail":{"type":"string"},"from":{"type":"string","description":"Alias de `fromEmail` (repo anterior). Se mapea a fromEmail."},"fromName":{"type":"string"},"replyTo":{"type":"string"},"projectId":{"type":"string"},"idempotencyKey":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object"},"unsubscribeLang":{"type":"string"},"attachments":{"description":"Adjuntos inline (base64), solo transporte (ADR-043). Se reenvían tal cual al\nenvío resuelto en `buildTemplateSendDto`.","type":"array","items":{"$ref":"#/components/schemas/AttachmentDto"}}},"required":["to"]},"BatchRecipientDto":{"type":"object","properties":{"to":{"type":"string","format":"email"},"vars":{"type":"object"}},"required":["to"]},"SendBatchDto":{"type":"object","properties":{"recipients":{"minItems":1,"maxItems":100,"type":"array","items":{"$ref":"#/components/schemas/BatchRecipientDto"}},"subject":{"type":"string","maxLength":998},"htmlBody":{"type":"string"},"html":{"type":"string"},"textBody":{"type":"string"},"text":{"type":"string"},"fromEmail":{"type":"string"},"from":{"type":"string"},"fromName":{"type":"string"},"replyTo":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object"},"idempotencyKey":{"type":"string"},"templateVersionId":{"type":"string"},"projectId":{"type":"string"},"unsubscribeLang":{"type":"string"},"attachments":{"description":"Adjuntos inline (base64) compartidos por TODOS los destinatarios del lote.\nNo hay adjunto por-destinatario. Cada envío individual cuenta el mismo tamaño.","type":"array","items":{"$ref":"#/components/schemas/AttachmentDto"}}},"required":["recipients","subject"]},"UpsertContactDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"externalId":{"type":"string","maxLength":128},"locale":{"type":"string"},"attributes":{"type":"object"},"optIn":{"type":"boolean"},"consentVersion":{"type":"string","maxLength":64},"source":{"type":"string","maxLength":64},"projectId":{"type":"string"}},"required":["email"]},"BulkUpsertContactsDto":{"type":"object","properties":{"contacts":{"minItems":1,"type":"array","items":{"$ref":"#/components/schemas/UpsertContactDto"}}},"required":["contacts"]},"PatchContactDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"externalId":{"type":"string","maxLength":128},"locale":{"type":"string"},"attributes":{"type":"object"},"optIn":{"type":"boolean"},"consentVersion":{"type":"string","maxLength":64},"source":{"type":"string","maxLength":64},"projectId":{"type":"string"}}},"AddTagsDto":{"type":"object","properties":{"tags":{"minItems":1,"maxItems":20,"type":"array","items":{"type":"string","maxLength":50,"pattern":"CONTACT_TAG_PATTERN"}}},"required":["tags"]},"CreateContactTagDto":{"type":"object","properties":{"name":{"type":"string","maxLength":50,"pattern":"CONTACT_TAG_PATTERN"},"color":{"type":"string","pattern":"^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$"},"description":{"type":"string","maxLength":200}},"required":["name"]},"UpdateContactTagDto":{"type":"object","properties":{"newName":{"type":"string","description":"Renombra el tag en el catalogo Y reescribe el string en todos los contactos del tenant.","maxLength":50,"pattern":"CONTACT_TAG_PATTERN"},"color":{"type":"string","pattern":"^#?([0-9A-F]{3}|[0-9A-F]{4}|[0-9A-F]{6}|[0-9A-F]{8})$"},"description":{"type":"string","maxLength":200}}},"CreateProjectDto":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"fromEmail":{"type":"string","format":"email"},"fromName":{"type":"string","minLength":1,"maxLength":120},"smtpHost":{"type":"string","maxLength":255},"smtpPort":{"type":"number","minimum":1,"maximum":65535},"smtpUser":{"type":"string","maxLength":255},"smtpPassword":{"type":"string","description":"Contraseña / app password SMTP en claro. Se cifra antes de guardar.","maxLength":512},"smtpSecure":{"type":"boolean"},"replyTo":{"type":"string","format":"email"}},"required":["name","fromEmail","fromName"]},"UpdateProjectDto":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"fromEmail":{"type":"string","format":"email"},"fromName":{"type":"string","minLength":1,"maxLength":120},"smtpHost":{"type":"string","maxLength":255},"smtpPort":{"type":"number","minimum":1,"maximum":65535},"smtpUser":{"type":"string","maxLength":255},"smtpPassword":{"type":"string","description":"Contraseña / app password SMTP en claro. Cadena vacía limpia la guardada.","maxLength":512},"smtpSecure":{"type":"boolean"},"replyTo":{"type":"string","format":"email"}}},"CreateDomainDto":{"type":"object","properties":{"domain":{"type":"string","maxLength":253,"pattern":"/^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$/"},"selector":{"type":"string","maxLength":32,"pattern":"/^[a-z0-9]+$/"}},"required":["domain"]},"UpdatePlatformSettingsDto":{"type":"object","properties":{}},"RenderReactEmailDto":{"type":"object","properties":{"sourceJsx":{"type":"string","maxLength":100000}},"required":["sourceJsx"]},"TemplateVariableDto":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["string","number","boolean","url","email","image","color"]},"fallback":{"type":"string"}},"required":["name","type"]},"CreateVersionDto":{"type":"object","properties":{"subject":{"type":"string"},"htmlBody":{"type":"string","description":"Requerido salvo editorMode=REACT_EMAIL (entonces se deriva de sourceJsx)."},"textBody":{"type":"string"},"mjmlSource":{"type":"string"},"sourceJsx":{"type":"string","maxLength":100000},"unlayerDesign":{"type":"object"},"variables":{"type":"array","items":{"$ref":"#/components/schemas/TemplateVariableDto"}},"editorMode":{"type":"object"},"locale":{"type":"string","nullable":true},"localeGroupId":{"type":"string","nullable":true}},"required":["subject","editorMode"]},"CreateTemplateDto":{"type":"object","properties":{"name":{"type":"string","minLength":2},"slug":{"type":"string","description":"Identificador estable para send-template. Si se omite, se deriva del nombre.","pattern":"/^[a-z0-9]+(?:-[a-z0-9]+)*$/"},"description":{"type":"string"},"projectId":{"type":"string"},"initialVersion":{"$ref":"#/components/schemas/CreateVersionDto"}},"required":["name","initialVersion"]},"Object":{"type":"object","properties":{}},"UpdateTemplateDto":{"type":"object","properties":{"name":{"type":"string","minLength":2},"slug":{"type":"string","pattern":"/^[a-z0-9]+(?:-[a-z0-9]+)*$/"},"description":{"type":"string"},"projectId":{"type":"string"}}},"UpdateVersionDto":{"type":"object","properties":{"subject":{"type":"string"},"htmlBody":{"type":"string"},"textBody":{"type":"string"},"mjmlSource":{"type":"string"},"sourceJsx":{"type":"string","maxLength":100000},"unlayerDesign":{"type":"object"},"variables":{"type":"array","items":{"$ref":"#/components/schemas/TemplateVariableDto"}},"editorMode":{"type":"object"},"locale":{"type":"string","nullable":true,"description":"es | en | it | fr | ca | de, or null for locale-neutral"},"localeGroupId":{"type":"string","nullable":true,"description":"Groups equivalent locale variants; null = self-anchored (defaults to version id at send time)"}}},"CreateSuppressionDto":{"type":"object","properties":{"email":{"type":"string","format":"email"},"reason":{"type":"object","default":"MANUAL"}},"required":["email"]},"AudienceFilterDto":{"type":"object","properties":{"locale":{"type":"string"},"optIn":{"type":"boolean"},"projectId":{"type":"string"},"attributes":{"type":"object"}}},"CreateCampaignDto":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"templateVersionId":{"type":"string"},"subject":{"type":"string","maxLength":998},"projectId":{"type":"string"},"audienceFilter":{"$ref":"#/components/schemas/AudienceFilterDto"},"timezone":{"type":"string"}},"required":["name"]},"PatchCampaignDto":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"templateVersionId":{"type":"string"},"subject":{"type":"string","maxLength":998},"projectId":{"type":"string"},"audienceFilter":{"$ref":"#/components/schemas/AudienceFilterDto"},"timezone":{"type":"string"}}},"TestCampaignDto":{"type":"object","properties":{"emails":{"minItems":1,"maxItems":5,"type":"array","items":{"type":"string","format":"email"}}},"required":["emails"]},"ScheduleCampaignDto":{"type":"object","properties":{"scheduledAt":{"type":"string"},"timezone":{"type":"string"}},"required":["scheduledAt"]},"ScheduleEmailDto":{"type":"object","properties":{"to":{"type":"string","format":"email"},"subject":{"type":"string","maxLength":998},"htmlBody":{"type":"string"},"html":{"type":"string","description":"Alias de `htmlBody` (repo anterior). Se mapea a htmlBody en el servicio."},"textBody":{"type":"string"},"text":{"type":"string","description":"Alias de `textBody` (repo anterior). Se mapea a textBody en el servicio."},"fromEmail":{"type":"string"},"from":{"type":"string","description":"Alias de `fromEmail` (repo anterior). Se mapea a fromEmail en el servicio."},"fromName":{"type":"string"},"replyTo":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object"},"headers":{"type":"object","description":"Cabeceras adicionales del mensaje (`Precedence`, `Auto-Submitted`, `References`…).\n\nEl transporte ya las soportaba (`sendViaTransport` las propaga y `buildRawMimeMessage`\nlas escribe), pero no estaban expuestas en el DTO: con `forbidNonWhitelisted` activo,\ncualquier envío que las mandara se rechazaba con 400 antes de crear el EmailLog, sin\ndejar rastro en los logs de envío.\n\nLas cabeceras de baja (`List-Unsubscribe`, `List-Unsubscribe-Post`) las pone la\nplataforma y tienen prioridad: no se pueden pisar desde aquí."},"idempotencyKey":{"type":"string"},"templateVersionId":{"type":"string"},"projectId":{"type":"string"},"unsubscribeLang":{"type":"string"},"trackingDisabled":{"type":"boolean","description":"Opt-out de tracking para este envío (privacidad/GDPR): si es `true`, no se inyecta el\npíxel de apertura ni se reescriben los enlaces por el redirector de clics. La cabecera\n`List-Unsubscribe` y el enlace de baja se mantienen (requeridos). Por defecto: tracking on."},"attachments":{"description":"Adjuntos inline (base64), solo transporte — no se persisten a largo plazo (ADR-043).\nEl servicio limita tamaño por fichero y total antes de enviar (413 EMAIL_TOO_LARGE).","type":"array","items":{"$ref":"#/components/schemas/AttachmentDto"}},"sendAt":{"type":"string"},"timezone":{"type":"string"}},"required":["to","subject","sendAt"]},"CreateSequenceDto":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":2000},"projectId":{"type":"string"},"triggerType":{"type":"object"},"triggerConfig":{"type":"object"}},"required":["name"]},"EnrollByEventDto":{"type":"object","properties":{"eventName":{"type":"string","minLength":1},"contactId":{"type":"string","minLength":1}},"required":["eventName","contactId"]},"PatchSequenceDto":{"type":"object","properties":{"name":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":2000},"projectId":{"type":"string"},"triggerType":{"type":"object"},"triggerConfig":{"type":"object","nullable":true}}},"CreateSequenceStepDto":{"type":"object","properties":{"stepType":{"type":"object"},"position":{"type":"number","minimum":0},"delayMinutes":{"type":"number","minimum":1},"templateVersionId":{"type":"string"},"subject":{"type":"string","maxLength":998}},"required":["stepType"]},"PatchSequenceStepDto":{"type":"object","properties":{"delayMinutes":{"type":"number","minimum":1},"templateVersionId":{"type":"string"},"subject":{"type":"string","maxLength":998},"condition":{"type":"object","nullable":true,"description":"Reserved for S4; accepted but not evaluated in S1."}}},"EnrollContactDto":{"type":"object","properties":{"contactId":{"type":"string","minLength":1}},"required":["contactId"]},"MemoClientMetadataDto":{"type":"object","properties":{"browser":{"type":"string","maxLength":500},"url":{"type":"string","maxLength":2048},"screenSize":{"type":"string","maxLength":40},"viewportSize":{"type":"string","maxLength":40},"timestamp":{"type":"string","maxLength":80},"projectName":{"type":"string","maxLength":120},"projectSlug":{"type":"string","maxLength":120}}},"CreateMemoDto":{"type":"object","properties":{"title":{"type":"string","maxLength":150},"description":{"type":"string","maxLength":2000},"category":{"type":"string","enum":["bug","suggestion","feature","improvement","question","other"]},"userName":{"type":"string","maxLength":100},"userEmail":{"type":"string","description":"Reply-To del aviso: formato + sin CR/LF (ADR-040). Se guarda en minúsculas (DSAR).","maxLength":254,"format":"email"},"screenshotBase64":{"type":"string","description":"Data URL `data:image/…;base64,…`. Mal formado se ignora; más de 5 MB decodificados → 413.","maxLength":7000000},"locale":{"type":"string","description":"Idioma del correo (`es`, `en-GB`, `it_IT`…); lo desconocido cae en `es`.","maxLength":16},"categoryLabel":{"type":"string","description":"Lo manda el widget; se ignora: la etiqueta sale del idioma del servidor.","maxLength":100},"icon":{"type":"string","description":"Lo manda el widget; se ignora: el icono sale de la categoría.","maxLength":16},"metadata":{"$ref":"#/components/schemas/MemoClientMetadataDto"},"website":{"type":"string","description":"Honeypot: un valor no vacío es un bot → 400.","maxLength":200},"startedAt":{"type":"number","description":"Inicio del rellenado (ms). Se acepta número o string numérico y se ignora: el tiempo\nmínimo de rellenado lo comprueba el servidor del sitio (ADR-047, punto 8)."},"browser":{"type":"string","maxLength":500},"url":{"type":"string","maxLength":2048},"screenSize":{"type":"string","maxLength":40},"viewportSize":{"type":"string","maxLength":40},"timestamp":{"type":"string","maxLength":80},"projectName":{"type":"string","maxLength":120},"projectSlug":{"type":"string","maxLength":120}},"required":["title","description","category","userName","userEmail"]},"CreateMemoSiteDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"projectId":{"type":"string","description":"Proyecto de envío del tenant: remitente del aviso y destinatario (su `replyTo`).","maxLength":64},"launcher":{"type":"object"}},"required":["name","projectId"]},"UpdateMemoSiteDto":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"projectId":{"type":"string","description":"Otro proyecto del tenant (remitente y destinatario del aviso).","maxLength":64},"launcher":{"type":"object"},"chatEnabled":{"type":"boolean"}}},"SetMemoReadDto":{"type":"object","properties":{"read":{"type":"boolean"}},"required":["read"]},"SetMemoStatusDto":{"type":"object","properties":{"status":{"type":"string","enum":["OPEN","RESOLVED"]}},"required":["status"]},"ReplyMemoDto":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":5000}},"required":["body"]},"PostMemoChatDto":{"type":"object","properties":{}},"GenerateDto":{"type":"object","properties":{"prompt":{"type":"string","maxLength":4000},"model":{"type":"string"},"systemPrompt":{"type":"string"},"task":{"type":"string","enum":["subjects","plain_text","general"]},"templateId":{"type":"string"},"versionId":{"type":"string"},"locale":{"type":"string","maxLength":10},"templateDescription":{"type":"string","maxLength":500},"currentSubject":{"type":"string","maxLength":200},"variables":{"type":"array","items":{"$ref":"#/components/schemas/TemplateVariableDto"}}},"required":["prompt"]},"GenerateTemplateDto":{"type":"object","properties":{"prompt":{"type":"string","maxLength":4000},"tone":{"type":"string","maxLength":120},"model":{"type":"string"},"templateId":{"type":"string"},"versionId":{"type":"string"},"locale":{"type":"string","maxLength":10},"templateDescription":{"type":"string","maxLength":500},"currentSubject":{"type":"string","maxLength":200},"variables":{"type":"array","items":{"$ref":"#/components/schemas/TemplateVariableDto"}}},"required":["prompt"]},"ImproveTemplateDto":{"type":"object","properties":{"html":{"type":"string","maxLength":50000},"sourceJsx":{"type":"string","maxLength":100000},"instruction":{"type":"string","maxLength":500},"model":{"type":"string"},"templateId":{"type":"string"},"versionId":{"type":"string"},"locale":{"type":"string","maxLength":10},"templateDescription":{"type":"string","maxLength":500},"currentSubject":{"type":"string","maxLength":200},"variables":{"type":"array","items":{"$ref":"#/components/schemas/TemplateVariableDto"}}},"required":["html","instruction"]},"UpsertAiPromptDto":{"type":"object","properties":{"title":{"type":"string","minLength":2,"maxLength":120},"systemPrompt":{"type":"string","minLength":10},"defaultModel":{"type":"string","maxLength":120},"temperature":{"type":"number","minimum":0,"maximum":2},"maxTokens":{"type":"number","minimum":1,"maximum":32000},"isActive":{"type":"boolean"}},"required":["title","systemPrompt"]},"CreateCheckoutDto":{"type":"object","properties":{"planSlug":{"type":"string"},"successUrl":{"type":"string"},"cancelUrl":{"type":"string"}},"required":["planSlug"]},"CreateTokenPackCheckoutDto":{"type":"object","properties":{"packId":{"type":"string"},"successUrl":{"type":"string"},"cancelUrl":{"type":"string"}},"required":["packId"]}}}}