MailLandDocs
Cuenta

Facturación

Administre su suscripción, vea facturas y monitoree el uso

MailLand utiliza Stripe para la gestión de suscripciones y facturación. Cada espacio de trabajo tiene su propia suscripción con precios basados en uso o en plan. Cualquier miembro puede leer el estado de facturación; solo el Owner del espacio de trabajo puede modificarlo (las llamadas de mutación devuelven 403 INSUFFICIENT_PERMISSIONS, y las claves API siempre son rechazadas en esos endpoints).

Estados de Pago

paymentStatus se devuelve como una cadena snake_case, no como un enum numérico:

EstadoDescripción
currentSuscripción activa, pago al día
grace_periodPago fallido, período de gracia activo
overduePago vencido, funciones restringidas
blockedCuenta bloqueada por falta de pago

Obtener Detalles de Suscripción

GET https://api.mail.land/v1/account/subscription
Get subscription details
curl https://api.mail.land/v1/account/subscription \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Subscription response
{
  "planName": "Pro",
  "monthlyEmailLimit": 100000,
  "rateLimitPerSecond": 10,
  "pricePerMonth": 49.00,
  "startDate": "2026-01-15T08:00:00Z",
  "endDate": "2026-03-01T00:00:00Z",
  "status": "Active",
  "paymentStatus": "current",
  "marketingPausedDueToPayment": false,
  "sendingBlockedDueToPayment": false,
  "transactionalDailyLimit": 5000,
  "daysUntilBlocked": null,
  "cancelAtPeriodEnd": false,
  "planFamilyId": "fam_pro",
  "planTierPublicId": "tier_pro_monthly",
  "usage": {
    "emailsSentThisMonth": 45000,
    "monthlyLimit": 100000,
    "percentageUsed": 45.0,
    "transactionalCount": 30000,
    "marketingCount": 12000,
    "apiCount": 40000,
    "smtpCount": 5000,
    "campaignCount": 3000,
    "automationCount": 2000,
    "inboundForwardCount": 500
  }
}

No hay id, planId, interval, currentPeriodStart/currentPeriodEnd, ni campos numéricos anidados de paymentStatus/validación/dominio/equipo/automatización en esta respuesta: use los nombres de campo anteriores. paymentStatus es una cadena snake_case: "current", "grace_period", "overdue" o "blocked". status está en PascalCase ("Active", "Suspended", "Cancelled"): la única excepción es el resultado sin suscripción, que devuelve "active" en minúsculas.

Campos de Uso

CampoDescripción
emailsSentThisMonthCorreos enviados en el período de facturación actual
monthlyLimitMáximo de correos por período
percentageUsedemailsSentThisMonth como porcentaje de monthlyLimit
transactionalCountCorreos transaccionales enviados
marketingCountCorreos de marketing enviados
apiCountCorreos enviados vía API
smtpCountCorreos enviados vía relé SMTP
campaignCountCorreos enviados por campañas
automationCountCorreos enviados por automatizaciones
inboundForwardCountCorreos enviados por reglas de reenvío de entrada

No hay contadores de uso de validación, dominio, miembros del equipo o automatización en esta respuesta: solo contadores de envío de correo.

Cuándo se cuenta el uso de correo

Los destinatarios cuentan contra su uso y cuota (emailsSentThisMonth / monthlyLimit) en el momento en que la aceptación se registra de forma duradera. Los destinatarios rechazados o suprimidos antes de la aceptación nunca cuentan. Un rebote, una supresión posterior, un fallo de entrega u otra no entrega que ocurra después de la aceptación no restaura ni recupera automáticamente el uso o la cuota: el conteo no se ajusta retroactivamente. Esta sección describe solo la contabilidad de uso; no establece ni implica precios de Stripe por correo ni ningún derecho de reembolso, que se rigen por separado por los términos de su suscripción.

La cuota se restablece en cada período de facturación de Stripe para los planes facturados a través de Stripe, o el día 1 de cada mes calendario UTC para los planes no facturados a través de Stripe (Free y planes otorgados por el administrador): no siempre es "por período" en el sentido de Stripe.

Planes y retención

Los planes son Free, Pro y Max. Los registros de mensajes se conservan 30 días en Free, 90 días en Pro y 180 días en Max.

Resumen de Política

Obtenga el estado de verificación del espacio de trabajo y la política de envío:

GET https://api.mail.land/v1/account/subscription/policy-summary
Get policy summary
curl https://api.mail.land/v1/account/subscription/policy-summary \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

La respuesta real es un objeto anidado, no plano (SubscriptionController.cs:137-200):

Policy summary response
{
  "subscription": {
    "planFamilyId": "fam_pro",
    "planFamilyName": "Pro",
    "planTierId": "tier_pro_monthly",
    "monthlyQuota": 100000,
    "pricePerMonth": 49.00
  },
  "usage": {
    "usedThisMonth": 45000,
    "remainingThisMonth": 55000,
    "percentUsed": 45.0
  },
  "effectiveRates": {
    "transactionalRatePerMin": 600,
    "marketingRatePerMin": 300,
    "isOverridden": false
  },
  "domainWarmup": [
    {
      "domainId": "h4k7m1n9w2p5x8",
      "domainName": "example.com",
      "currentStage": 2,
      "totalStages": 5,
      "todaySentCount": 350,
      "dailyLimit": 500,
      "progressPercent": 70.0,
      "completed": false,
      "bypassed": false
    }
  ],
  "alerts": [
    {
      "type": "warning",
      "code": "QUOTA_WARNING",
      "message": "You have used 80% of your monthly quota. Consider upgrading your plan.",
      "actionUrl": "/billing"
    }
  ],
  "dailySendingLimit": {
    "limit": 5000,
    "usedToday": 1200,
    "remainingToday": 3800,
    "resetsAt": "2026-02-18T00:00:00Z"
  },
  "verification": {
    "level": 2,
    "levelName": "SenderVerified",
    "limits": {},
    "progress": {},
    "nextSteps": []
  }
}
CampoDescripción
subscriptionFamilia del plan, nivel y cuota/precio mensual
usageCorreos usados, restantes y el porcentaje usado este mes
effectiveRatesTasas de envío efectivas por minuto y si están sobrescritas
domainWarmupProgreso de calentamiento por dominio, una entrada por dominio en calentamiento
alertsAlertas activas para este espacio de trabajo (cuota, límite diario y similares)
dailySendingLimitLímite de envío diario y margen restante, cuando aplica
verificationNivel de verificación actual, sus límites, progreso y próximos pasos

Crear Sesión de Pago

Inicie una sesión de Stripe Checkout para suscribirse o actualizar su plan:

POST https://api.mail.land/v1/account/billing/checkout
Checkout request
{
  "planTierId": "tier_pro_monthly",
  "locale": "en",
  "businessAttested": true,
  "businessAttestationKey": "business-use-v3-button"
}
CampoTipoRequeridoDescripción
planTierIdstringSíId público del nivel de plan
localestringNoIdioma para la página de pago alojada
businessAttestedbooleanSítrue confirma que compra MailLand para uso empresarial o profesional (incluso como autónomo, empresario individual o para su propio sitio web). El panel lo envía en el botón de pago: su etiqueta dice «Pay for business use» y una nota de una línea debajo indica qué confirma el clic
businessAttestationKeystringSíLa versión del texto a la que se refiere la confirmación; actualmente business-use-v3-button (business-use-v1, el texto anterior, se sigue aceptando)

Una solicitud sin businessAttested: true y sin un businessAttestationKey aceptado se rechaza con 400 BUSINESS_ATTESTATION_REQUIRED antes de cobrar nada. MailLand guarda quién confirmó, cuándo, con qué texto (la clave que usted envió) y en qué idioma. En Stripe Checkout puede introducir un identificador fiscal; es opcional. Los precios no incluyen IVA y MailLand no cobra IVA; un NIF-IVA de la UE verificado, fuera del Reino Unido, añade la nota de inversión del sujeto pasivo a sus facturas.

No hay campo successUrl ni cancelUrl: las URLs de éxito/cancelación no son proporcionadas por quien llama.

Create checkout session
curl -X POST https://api.mail.land/v1/account/billing/checkout \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{ "planTierId": "tier_pro_monthly", "locale": "en", "businessAttested": true, "businessAttestationKey": "business-use-v3-button" }'
Checkout response
{
  "upgraded": false,
  "sessionId": "cs_live_abc123...",
  "url": "https://checkout.stripe.com/c/pay/cs_live_abc123..."
}

Redirija al usuario a la url para completar el pago en la página de pago alojada por Stripe. Si el espacio de trabajo ya tiene una suscripción activa, el plan se cambia en el mismo lugar en lugar de abrir un nuevo checkout: la respuesta es { "upgraded": true } sin sessionId/url, y no hay redirección. Solo redirija cuando url esté presente.

Portal de Facturación

Abra el Portal del Cliente de Stripe para la gestión de autoservicio (actualizar método de pago, cancelar, ver facturas):

POST https://api.mail.land/v1/account/billing/portal
Portal request
{
  "locale": "en"
}

locale es opcional.

Open billing portal
curl -X POST https://api.mail.land/v1/account/billing/portal \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{ "locale": "en" }'
Portal response
{
  "url": "https://billing.stripe.com/p/session/abc123..."
}

Redirija al usuario a la url para acceder al portal de Stripe.

Listar Facturas

GET https://api.mail.land/v1/account/billing/invoices
ParámetroTipoPredeterminadoDescripción
limitint20Número de facturas a devolver
cursorstring-Cursor opaco del nextCursor de una respuesta anterior
List invoices
curl https://api.mail.land/v1/account/billing/invoices \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Invoices response
{
  "items": [
    {
      "publicId": "inv_abc123",
      "invoiceNumber": "INV-2026-0015",
      "stripeInvoiceId": "in_1AbCdEfGhIjKlMn",
      "status": "Paid",
      "amountDue": 4900,
      "amountPaid": 4900,
      "currency": "eur",
      "periodStart": "2026-01-01T00:00:00Z",
      "periodEnd": "2026-02-01T00:00:00Z",
      "paidAt": "2026-01-01T00:05:00Z",
      "hostedInvoiceUrl": "https://pay.stripe.com/invoice/inv_abc123",
      "invoicePdfUrl": "https://pay.stripe.com/invoice/inv_abc123/pdf",
      "createdAt": "2026-01-01T00:00:00Z"
    },
    {
      "publicId": "inv_def456",
      "invoiceNumber": "INV-2026-0014",
      "stripeInvoiceId": "in_2BcDeFgHiJkLmNo",
      "status": "Paid",
      "amountDue": 4900,
      "amountPaid": 4900,
      "currency": "eur",
      "periodStart": "2025-12-01T00:00:00Z",
      "periodEnd": "2026-01-01T00:00:00Z",
      "paidAt": "2025-12-01T00:05:00Z",
      "hostedInvoiceUrl": "https://pay.stripe.com/invoice/inv_def456",
      "invoicePdfUrl": "https://pay.stripe.com/invoice/inv_def456/pdf",
      "createdAt": "2025-12-01T00:00:00Z"
    }
  ],
  "nextCursor": null,
  "hasMore": false
}

Esta es una respuesta paginada por cursor, no { "invoices": [...] }: pase nextCursor de vuelta como el parámetro cursor para obtener la siguiente página, y deténgase cuando hasMore sea false. El tamaño de página predeterminado es 20, no 10; los nombres de campo son invoiceNumber, amountDue, amountPaid, hostedInvoiceUrl e invoicePdfUrl (no number, amount, invoiceUrl, invoicePdf).

Los montos de las facturas están en la unidad más pequeña de la currency de la factura (céntimos para EUR). Divida entre 100 para mostrarlos. Los precios de los planes están en euros (EUR) y no incluyen IVA.

Respuestas de Error

EstadoCódigoDescripción
400VALIDATION_FAILEDCuerpo de solicitud inválido
400INVALID_REQUESTEl nivel de plan existe pero no está sincronizado con Stripe
403INSUFFICIENT_PERMISSIONSSolo el Owner del espacio de trabajo puede realizar esta mutación (la lectura de facturación está abierta a cualquier miembro)
404RESOURCE_NOT_FOUNDNivel de plan desconocido o inactivo
502STRIPE_ERRORLa solicitud a Stripe falló

Otros Endpoints de Facturación

También disponibles, no detallados arriba: POST /v1/account/billing/cancel, POST /v1/account/billing/reactivate, y el endpoint público GET /public/plans/catalog.

Pasos Siguientes

En esta página