Skip to content

MailerLite Technical Integration

Technical reference for IxDF's MailerLite integration. For business context, see mailerlite-overview.md.

Architecture

Data Flow

Outbound: App → MailerLite

Payload: email, name, country, member_status, membership_plan_category, membership_expire_at

Inbound: MailerLite → App

Payload Fields

Fields sent to MailerLite (see overview for field descriptions):

php
// Subscriber::getMembershipStatus()
if (no membership found)  "non-member"
if (membership.canceled)  "canceled"
else "active-or-expired"  // Grouped to avoid daily sync churn

Why "active-or-expired"? Separating active from expired would cause daily sync churn as memberships expire.

Key Files

ComponentPath
Configurationconfig/ixdf_mailerlite.php
Service ProviderSubscription/SubscriptionServiceProvider.php
API ManagerSubscription/Services/MailerLite/MailerLiteSubscriberDataManager.php
Sync JobSubscription/Jobs/MailerLite/SendSubscriberData.php
Payload DTOSubscription/Services/MailerLite/SubscriberPayload.php
Subscriber EventSubscription/Listeners/UpdateSubscriberInExternalList.php
Membership EventSubscription/Listeners/UpdateMembershipInExternalList.php
Webhook HandlerSubscription/Http/Controllers/Webhooks/MailerLite/UpdateSubscriberStatusController.php
VerificationSubscription/Actions/VerifySubscriberInMailerLiteAction.php

Error Handling

Retryable Errors (auto-retry for 12h)

  • HTTP 408 Request Timeout
  • HTTP 429 Too Many Requests
  • HTTP 5xx Server Errors

Non-Retryable Errors (logged, job fails)

  • HTTP 4xx Client Errors (validation failures)
  • Invalid API key
  • Malformed payload

Exception Classes

text
MailerLiteRetryableIssue      → Transient failures, will retry
MailerLiteNotRetryableIssue   → Permanent failures, logged
MailerLiteUnclassifiedApiResponse → Unknown status, logged for investigation

Rate Limiting

By early 2026, MailerLite has a limit of 60 req/min.

php
// Configured in SubscriptionServiceProvider
RateLimiter::for('api:mailerlite', fn() => [
    Limit::perMinute(60),
    Limit::perSecond(1),
]);

// Applied via job middleware
public function middleware(): array
{
    return [new RateLimited('api:mailerlite')];
}

Testing & Debugging

Verify Sync Status

php
// Via Nova action or tinker
$action = new VerifySubscriberInMailerLiteAction();
$result = $action->execute($subscriber);

// Returns: ['found' => bool, 'synced' => bool, 'issues' => [...]]

Manual Sync

php
// Force sync a subscriber
dispatch(new SendSubscriberData($subscriber));

Health Check

bash
# Module-level health:check contains mailerlite part:
php artisan subscription:health:check --mailerlite-sample=10

# Check whether MailerLite webhooks integration is enabled:
php artisan subscription:mailerlite:check-webhook

Common Issues

SymptomCauseSolution
Subscriber not in MailerLiteJob failed or still queuedCheck Horizon; re-dispatch job
Wrong segment membershipmember_status out of syncTrigger membership update event
Webhook not processingSignature mismatchVerify secret in .env
Rate limit errorsToo many concurrent syncsJobs auto-retry; wait for backlog