Para desarrolladores

Cree plugins. No parches.

AcelleMail es una plataforma de email marketing en Laravel 11+ que se entrega con el código fuente PHP completo y sin cifrar, y un sistema de Hooks tipado que permite que sus plugins añadan drivers de envío, pasarelas de pago, IA, UI personalizada e incluso REST APIs. Sin bifurcar el core.

Plugins reales en producción hoy

acelle/ai athena/evs rencontru/postal acelle/console
myvendor/loyalty/ PLUGIN SOURCE composer.json 240 B routes.php 1.2 KB src/ ServiceProvider.php entry Controllers/ Models/ database/migrations/ resources/ views/ lang/ index.json auto $ php artisan plugin:init … HOOK SYSTEM no core touches ACELLEMAIL Laravel 11+ · PHP 8.3+ layout.head.assets layout.body.close admin.sidebar.groups register_sending_* page.{ctrl}.{slot} customer_added sidebar-menu-items dispatch_*_job + many more…

Por qué los desarrolladores eligen AcelleMail

Construido sobre el framework que ya conoce.
Extendido mediante patrones que ya usa.

PHP / Laravel de código abierto

El código fuente PHP completo y sin cifrar se entrega con cada licencia. Modifique cualquier clase, sobrescriba cualquier servicio, bifurque hacia su propio namespace: su código, sus reglas. Construido sobre Laravel 11+, para que el framework que ya conoce haga el trabajo pesado.

$ grep -r "protected function" vendor/acelle/

Arquitectura de plugins

Coloque una carpeta con forma de paquete Composer en storage/app/plugins/<vendor>/<name>/ y la aplicación la autocarga. El ServiceProvider inyecta rutas, vistas, migraciones y hooks: active, desactive y elimine sin dejar residuos.

$ php artisan plugin:init myvendor/loyalty

REST API con autenticación por token

Endpoints CRUD para campañas, listas, suscriptores, plantillas y automatizaciones. Eventos webhook para cada suceso a nivel de dominio. Listo para frontends SaaS, apps móviles u otros servicios Laravel. La misma API que usan los plugins es la que usan los clientes externos: sin endpoints de segunda clase.

GET /api/v1/campaigns · POST /api/v1/lists

Autoalojado en su infraestructura

Su servidor, su base de datos, los datos de sus suscriptores. Sin dependencia del proveedor. Pague una vez por la licencia; pague solo el coste subyacente del SMTP (p. ej., Amazon SES a $0.10/1K). Despliegue donde sea que se ejecute PHP: bare metal, Kubernetes, Forge, Laravel Vapor. Escale como escale su stack.

· PHP 8.3+ · MySQL / MariaDB · Redis (optional)

Lo que puede construir con plugins

14 puntos de extensión.
Cada uno con un ejemplo real en producción hoy.

Un plugin es un paquete Laravel autónomo que reside en disco, tiene su propio namespace, sus propias tablas de base de datos, rutas, vistas, controladores y modelos, y se integra con el core a través de un sistema de Hooks tipado en lugar de trucos con include.

Drivers e integraciones · 4

Servidores de envío / drivers REGISTRY
register_sending_server_driver
rencontru/postal — driver de Postal MTA como un único plugin listo para usar
Verificación de email / entregabilidad REGISTRY
REGISTRY + FILTER
athena/evs — subsistema de verificación con UI de administración
Pasarelas de pago REGISTRY
REGISTRY
Stripe / PayPal / Braintree / Paystack / Razorpay / Coinbase integrados muestran el patrón
IA / chatbot / asistentes REGISTRY
REGISTRY + EVENT
acelle/ai — chatbox + sparkle + observabilidad

UI y páginas · 5

Inyección de UI personalizada REGISTRY
layout.head.assets / layout.body.before_close / admin.sidebar.groups
acelle/ai chatbox + popover de sparkle
Slots de contenido a nivel de página REGISTRY
page.{ctrl}.{action}.{slot}
page.maillist.show.body, page.campaign.index.sidebar
Páginas de administración ROUTE
Laravel routes
/rui/admin/ai-usage, /rui/admin/ai-audit, /rui/admin/ai-conversations
Páginas de cara al cliente ROUTE
Laravel routes
/plugins/acelle/ai/dashboard
REST APIs ROUTE
Routes + api.access_token
/api/v1/ai/* en acelle/ai

Datos y ciclo de vida · 2

Modelos Eloquent personalizados + tablas de BD BEHAVIOR
Plugin-isolated migrations
acelle/ai incluye 8 modelos / 12 migraciones, con nombres de tabla prefijados por el vendor
Traducciones (18 locales) REGISTRY
add_translation_file
acelle/ai incluye 162 archivos de idioma (18 × 9)

Comportamiento y flujo · 3

Listeners de webhook / eventos de dominio EVENT
Hook::on(…)
customer_added, plan_changed, subscription_terminated
Sobrescrituras de comportamiento BEHAVIOR
Hook::set / setIfEmpty / perform
dispatch_list_import_job — reemplace por completo la lógica de importación
Cadenas de filtros FILTER
Hook::modify / filter
sidebar-menu-items, mutación de contenido antes del envío, URLs de redirección

Un solo plugin puede combinar cualquiera de estos puntos: acelle/ai usa 7 de 14 en un único paquete.

El sistema de Hooks

Cuatro patrones de extensión tipados. Sin sobrescrituras sorpresa. Sin conflictos silenciosos.

El core nunca importa el código de los plugins: solo declara puntos de extensión. Los plugins escuchan y reaccionan. Cuatro patrones, cada uno con un rol claro. Los conflictos lanzan una excepción de inmediato.

1

REGISTRY add() + collect()

El plugin aporta elementos a una lista. El core pregunta «¿quién tiene un driver de envío?» y su plugin responde «yo tengo uno».


Hook::add('register_sending_server_driver', fn () => [
    'type'   => 'myvendor-foo',
    'driver' => \MyVendor\Foo\Driver::class,
]);


$drivers = Hook::collect('register_sending_server_driver');
2

EVENT on() + fire()

El plugin reacciona a algo que ocurre. Los valores devueltos se descartan.


Hook::on('customer_added', function ($customer) {
    LoyaltyPoints::award($customer, 100, 'welcome');
});


Hook::fire('customer_added', [$customer]);
3

BEHAVIOR set() + perform()

El plugin reemplaza por completo una parte de la lógica del core. Solo un plugin puede reclamar un comportamiento dado: los conflictos lanzan una excepción de inmediato.


Hook::set('dispatch_list_import_job',
    fn ($list, $f) => new MyFasterImportJob($list, $f));


Hook::setIfEmpty('dispatch_list_import_job',
    fn ($list, $f) => new DefaultImportJob($list, $f));
$job = Hook::perform('dispatch_list_import_job', [$list, $f]);
dispatch($job);
4

FILTER modify() + filter()

El plugin transforma un valor a través de una cadena de callbacks. Cada callback recibe el valor actual y devuelve el valor modificado.


Hook::modify('sidebar-menu-items', function (array $items) {
    $items[] = [
        'label' => 'Loyalty',
        'url'   => route('lp.dashboard'),
    ];
    return $items;
});


$menu = Hook::filter('sidebar-menu-items', $defaultMenu);

Hello World en 5 minutos

Un plugin funcional desde cero en ocho comandos.

El scaffold lo crea todo: metadatos de Composer, ServiceProvider, modelo de ejemplo, migración de ejemplo, ruta de ejemplo y vista de ejemplo. A partir de ahí, es suyo para hacerlo crecer.

  1. 1

    Genere el scaffold del plugin

    Crea la estructura de carpetas estándar y una fila inactiva en la BD.

    bash
    $ php artisan plugin:init myvendor/loyalty
      ✓ Created storage/app/plugins/myvendor/loyalty/
      ✓ DB row inserted  (status: inactive)
      ✓ index.json + ServiceProvider autoloaded
  2. 2

    Edite composer.json

    Informe a Composer sobre su namespace y el ServiceProvider.

    json
    {
      "name": "myvendor/loyalty",
      "description": "Award points on signup",
      "version": "1.0.0",
      "autoload":  { "psr-4": { "MyVendor\\Loyalty\\": "src/" } },
      "extra":     { "laravel": { "providers": [
        "MyVendor\\Loyalty\\ServiceProvider"
      ] } }
    }
  3. 3

    Escriba una migración

    Tabla aislada del plugin, con nombre prefijado por el vendor. Se ejecuta al activar y se revierte al eliminar.

    php
    Schema::create('myvendor_loyalty_accounts', function (Blueprint $t) {
        $t->id();
        $t->foreignId('customer_id')->constrained()->cascadeOnDelete();
        $t->integer('points')->default(0);
        $t->timestamps();
    });
  4. 4

    Defina un modelo

    Modelo Eloquent estándar en su propio namespace.

    php
    namespace MyVendor\Loyalty\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Account extends Model
    {
        protected $table    = 'myvendor_loyalty_accounts';
        protected $fillable = ['customer_id', 'points'];
    }
  5. 5

    Añada un controlador y una vista

    Controlador Laravel normal: el namespace de la vista es el nombre de su plugin.

    php
    namespace MyVendor\Loyalty\Controllers;
    
    use Acelle\Http\Controllers\Controller;
    
    class DashboardController extends Controller
    {
        public function index()
        {
            return view('loyalty::dashboard', [
                'accounts' => \MyVendor\Loyalty\Models\Account::orderByDesc('points')->take(10)->get(),
            ]);
        }
    }
  6. 6

    Declare las rutas

    El mismo Route::group que ya usa. Lo carga ServiceProvider::boot().

    php
    Route::group([
        'middleware' => ['web', 'auth'],
        'namespace'  => '\MyVendor\Loyalty\Controllers',
        'prefix'     => 'plugins/myvendor/loyalty',
    ], function () {
        Route::get('/',          'DashboardController@index')->name('lp.dashboard');
        Route::get('/{account}', 'DashboardController@show');
    });
  7. 7

    Conéctelo todo en ServiceProvider::boot()

    Cargue vistas y rutas; engánchese a activate_plugin_… para migrar al activar.

    php
    public function boot(): void
    {
        $this->loadViewsFrom (__DIR__.'/../resources/views', 'loyalty');
        $this->loadRoutesFrom(__DIR__.'/../routes.php');
    
        Hook::on('activate_plugin_myvendor/loyalty', fn () =>
            \Artisan::call('migrate', [
                '--path'  => 'storage/app/plugins/myvendor/loyalty/database/migrations',
                '--force' => true,
            ])
        );
    
        Hook::on('customer_added', fn ($customer) =>
            Models\Account::create(['customer_id' => $customer->id, 'points' => 100])
        );
    }
  8. 8

    Actívelo desde administración

    Vaya a /rui/admin/plugins. Las migraciones se ejecutan automáticamente. El plugin vive en su prefijo.

    bash
    ✓ activated  myvendor/loyalty  v1.0.0
      → migrations: 1 ran (myvendor_loyalty_accounts)
      → routes:     2 registered under /plugins/myvendor/loyalty
      → hooks:      2 listening (activate, customer_added)
      → status:     active
    
    → visit /plugins/myvendor/loyalty/  ← live

Ya tiene un plugin funcional. Añada tantos modelos, controladores y hooks como exija su funcionalidad. Los tests viven en tests/; ejecútelos con php artisan test --testsuite='Plugin: myvendor/loyalty'. Consulte el contrato canónico en la base de conocimiento.

Ciclo de vida del plugin

Cuatro estados. Transiciones predecibles. Sin el misterio de «¿se ejecutó?».

Cada plugin vive en exactamente uno de cuatro estados. El estado en el que se encuentra determina qué hooks se disparan, qué migraciones se han ejecutado y qué ocurre en la siguiente transición. Fundamentado en el código de docs/plugin/SOURCE_OF_TRUTH.md.

STATE 01 register (inactivo) Carpeta del plugin descubierta. Existen index.json y la fila en la BD. Los hooks NO se disparan. STATE 02 active Todos los hooks activos. Rutas montadas. Migraciones ejecutadas. activate_plugin_… disparado una vez. STATE 03 inactive (en pausa) La carpeta sigue en disco. Hooks en pausa. Rutas desmontadas. Tablas de la BD intactas. STATE 04 deleted (eliminado) Carpeta eliminada. Migraciones revertidas si $keepData = false. Fila de la BD eliminada. activate migraciones ejecutadas deactivate datos conservados remove $keepData? re-activate el hook activate NO se vuelve a ejecutar
Register · inactivo

Descubierto, sin ejecutarse

La carpeta del plugin existe, index.json está indexado y la fila de la BD indica inactive. El register() del ServiceProvider se ejecutó, pero los hooks de boot() están bloqueados hasta que haga clic en Activar.

Active

Activo, hooks disparándose

La primera activación dispara activate_plugin_<name> una vez: es aquí donde se ejecutan las migraciones. A partir de entonces, todos los hooks REGISTRY / EVENT / FILTER / BEHAVIOR están activos hasta que se desactiven.

Inactive · en pausa

En pausa, datos intactos

Las rutas se desmontan, los hooks se bloquean, pero la carpeta y las tablas de la BD permanecen. Reactivar no vuelve a ejecutar las migraciones ni el hook activate: es seguro alternarlo en producción.

Deleted

Eliminado sin residuos

Carpeta eliminada, fila de la BD borrada. Si $keepData = false, las migraciones del plugin se revierten: las tablas prefijadas por el vendor se eliminan. Las tablas del core nunca se tocan.

Muestra de un plugin real

acelle/ai — un subsistema de IA completo en una sola carpeta de plugin.

El plugin acelle/ai incluye una capa de asistente de IA completa: chatbox del agente en cada página, reescritura de texto Sparkle ✨ en los campos de texto enriquecido, asistentes coach fundamentados en la KB (Entregabilidad, Segmentos, Campañas, Formularios) y una superficie de observabilidad de administración repartida en 5 rutas. Se monta mediante 3 hooks de layout. Cero cambios en el core.

El plugin acelle/ai en acción: burbuja flotante del chatbox de IA de AcelleMail con el popover Sparkle ✨ para reescritura con un clic, además del grupo de barra lateral de administración del plugin renderizado dentro de la UI de AcelleMail

Lo que incluye

  • Chatbox flotante: modo soporte simple + modo agente opcional que llama a herramientas
  • Popover Sparkle: reescritura / ampliación / simplificación con un clic en cada campo de texto enriquecido
  • Asistentes coach: ayudantes LLM que conocen su dominio, acotados por pantalla
  • Observabilidad de administración: uso, auditoría, conversaciones, valoraciones y autosuperación
  • Flexibilidad de motor: use su propio OpenAI, Anthropic u Ollama local
  • Página de aterrizaje del plugin en /plugins/acelle/ai/dashboard

En cifras

8
Modelos Eloquent
12
Migraciones
60+
Plantillas Blade
100+
Tests Pest
18 × 9
Locales × archivos de idioma
~35
Archivos CSS + JS

Cómo se monta: 3 hooks

acelle/ai plugin → CSS / JS assets Hook::add( 'layout.head.assets', fn()=>...); → Chatbox bubble Hook::add( 'layout.body.before_close' ,fn()=>...); → AI sidebar group Hook::add( 'admin.sidebar.groups', fn()=>...); Self-contained. AcelleMail core <head> + acelle-ai-chatbox.css </body> (just before) + <div class="ai-chatbox"> Admin sidebar AI · Settings AI · Usage AI · Conversations

3 hooks REGISTRY de layout, y ya está. Más inyecciones por página, listeners de eventos del ciclo de vida y una REST API propia con namespace en /api/v1/ai/*. Cero cambios en el core; la carpeta del plugin se despliega lista para usar.

REST API

Endpoints autenticados por token. La misma API que usan los plugins.

Use la REST API para integrar AcelleMail en su propio frontend SaaS, app móvil o servicio Laravel. La misma API que usan los plugins es la que usan los clientes externos: sin endpoints de segunda clase.

Recursos

  • ListasGET/POST/PATCH/DELETE /api/v1/lists[/:uid]
  • Suscriptores/api/v1/subscribers · etiquetas · alta/baja
  • Campañas/api/v1/campaigns[/:uid] · ejecutar/pausar/reanudar · CSVs de registro
  • Automatizaciones/api/v1/automations[/:uid] · ejecutar · api/call
  • Servidores de envío/api/v1/sending_servers[/:uid]
  • Clientes (admin)/api/v1/customers[/:uid] · asignar/cambiar-plan · habilitar/deshabilitar
  • Suscripciones (admin)/api/v1/subscriptions[/:uid]

Eventos webhook

Ciclo de vida (configurado en Administración → Webhooks): new_customer, new_subscription, change_plan, cancel_subscription, terminate_subscription, automation_webhook.
Seguimiento por destinatario (por campaña): open, click, unsubscribe.

Referencia completa de la API →
# Create a list
$ curl -X POST \
    https://your-acelle.example.com/api/v1/lists \
    -H "Authorization: Bearer $ACELLE_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Newsletter",
      "from_email": "hi@example.com",
      "from_name": "Hi Team",
      "subject": "Weekly digest"
    }'

# Add a subscriber
$ curl -X POST \
    .../api/v1/lists/:uid/subscribers \
    -H "Authorization: Bearer $ACELLE_TOKEN" \
    -d '{"EMAIL":"alice@example.com"}'

# Send a campaign
$ curl -X POST \
    .../api/v1/campaigns/:uid/send \
    -H "Authorization: Bearer $ACELLE_TOKEN"

# Receive a webhook
POST /your-webhook-endpoint
{
  "event": "campaign.sent",
  "campaign_uid": "abc123",
  "list_uid": "xyz789",
  "sent_at": "2026-05-06T12:34:56Z"
}

Filosofía de código abierto

Su código, para siempre. Sin cajas negras, sin cuotas recurrentes, sin secuestro de namespaces.

Código sin cifrar

Cada línea de PHP que se ejecuta en su servidor. Sin ionCube, sin SourceGuardian, sin ofuscación. Haga git diff de sus personalizaciones. Use grep para encontrar lo que sea.

Actualizaciones de por vida

Cada versión de AcelleMail desde 2016 está en su historial de descargas de CodeCanyon. Descargue lo que quiera cuando quiera. Sin presión de suscripción.

Su namespace, para siempre

Los plugins viven bajo MyVendor\MyPlugin\, completamente aislados del core Acelle\*. Distribuibles vía Composer a su equipo o a un marketplace.

Licencia de pago único

Pague $80 (Regular) o $199 (Extendida, para SaaS). Sin suscripciones, sin cargos por suscriptor, sin cargos por email. Las cuentas no cambian a medida que crece.

Recursos y comunidad

Documentación, plugins de ejemplo y una línea directa con el soporte.

Documentación completa para desarrolladores

Once análisis a fondo fundamentados en el código. Vaya directo a la página que necesita:

Explorar el hub →

Guía de desarrollo de plugins

Cinco archivos del lado del host, el flujo de arranque y carga, los cuatro estados del ciclo de vida y las dos capas de inyección: el modelo mental que asume el resto de la documentación.

/developers/plugin-architecture →

Referencia de la REST API

Autenticación, catálogo de endpoints, payloads de webhook y formatos de error: página nativa con ejemplos.

/api →

El sistema de Hooks — cuatro patrones

REGISTRY / EVENT / BEHAVIOR / FILTER: las cuatro formas de extensión que usan los plugins, con call-sites reales extraídos del core con grep, la semántica de conflictos y seis antipatrones.

/developers/hook-system →

Drivers de envío — patrón completo de plugin

Lance un backend MTA completamente nuevo sin bifurcar el core. El contrato register_sending_server_driver, nueve marcadores de capacidad y cinco trampas del plugin de Postal.

/developers/sending-drivers →

Muestra de plugin — acelle/ai

El plugin complejo canónico recorrido de principio a fin. Ocho modelos, catorce migraciones, dieciocho locales, todas las superficies de hook, la UI del chatbox y una receta de aprendizaje en cuatro pasos.

/developers/showcase →

Soporte para desarrolladores

¿Atascado con un contrato de hook o una duda sobre el ciclo de vida de un plugin? Escríbanos: respuesta habitual en 24 h.

support@acellemail.com →
Índice de documentación · CAT

Explore los 11 análisis a fondo →

Fundamentos, Construcción, Calidad, Referencia: todas las páginas en un solo lugar, fundamentadas en el código de storage/app/plugins/acelle/ai/ y en la documentación canónica de plugins.

/developers →

FAQ para desarrolladores

Las preguntas que los desarrolladores hacen de verdad antes de comprar.

¿Puedo modificar el código fuente del core sin perder las actualizaciones? +

Sí, pero el patrón más limpio es un plugin. Los plugins viven fuera del namespace del core y sobreviven a cada actualización automáticamente. Editar el core directamente funciona, pero obliga a fusionar manualmente los cambios upstream en cada versión. El sistema de plugins existe precisamente para evitar ese trabajo tedioso.

¿Sobreviven los plugins a las actualizaciones de AcelleMail? +

Sí, por diseño. El core declara puntos de hook; los plugins reaccionan. Mientras el nombre y la firma del hook se mantengan estables (y marcamos con versión los cambios incompatibles), su plugin sigue funcionando. Probamos el plugin de IA (acelle/ai) en cada versión.

¿Puedo vender plugins comercialmente? +

Sí. La Licencia Extendida le permite distribuir sus propios plugins bajo su propia licencia. Los plugins viven en su propio namespace; usted es dueño de ese código al 100%. Varios equipos gestionan marketplaces privados para sus ecosistemas internos de plugins.

¿Cómo gestiona los conflictos el sistema de plugins? +

Los hooks REGISTRY se fusionan (cada plugin aporta); los hooks EVENT se disparan todos (sin conflicto posible); las cadenas FILTER se acumulan; BEHAVIOR es el único patrón «exclusivo»: si dos plugins intentan reclamar el mismo comportamiento, se lanza una excepción de inmediato. Sin sorpresas de sobrescritura silenciosa.

¿Pueden comunicarse los plugins entre sí? +

Sí, a través del mismo sistema de Hooks. El Plugin A puede disparar eventos para que el Plugin B los escuche. O exponer una clase pública: MyVendor\PluginA\Service es una clase PHP normal, importable como cualquier otra. El plugin acelle/ai expone hooks para que otros plugins registren herramientas de IA personalizadas.

¿Cuál es la diferencia entre Regular y Extendida para un desarrollador? +

La Regular ($80) cubre su propio uso en un único dominio. La Extendida ($199) añade el derecho a cobrar a los usuarios finales (revender como SaaS), distribuir clones de marca blanca y vender sus propios plugins. Ambas incluyen el mismo código fuente.

¿Las migraciones de los plugins tocan la BD principal? +

Escriben en la misma base de datos, pero en tablas prefijadas con el nombre de su vendor (p. ej., myvendor_loyalty_accounts). Las migraciones se ejecutan al activar el plugin y se revierten al eliminarlo con $keepData = false. Cero riesgo para las tablas del core.

¿Puedo escribir plugins en algo que no sea PHP? +

El runtime de los plugins es PHP/Laravel. Pero su plugin puede invocar lo que sea por la shell: servicios Node, ML en Python, binarios Go, APIs HTTP externas. Varios equipos publican plugins que envuelven herramientas externas. El plugin es la cáscara de integración; el trabajo pesado puede vivir en cualquier sitio.

¿Cómo interactúan los plugins con el subsistema de IA? +

acelle/ai expone hooks que otros plugins pueden usar para registrar herramientas de IA personalizadas, cambiar de motor o engancharse a la capa de observabilidad. Lea el código fuente del plugin de IA para conocer el contrato. Su plugin también puede disparar eventos que el agente de IA recoge como contexto.

¿Existe un marketplace de plugins? +

Todavía no. Hoy, los plugins se distribuyen por venta directa, GitHub o su registro privado. Un marketplace comunitario está en el roadmap, una vez que existan suficientes plugins de terceros para que valga la pena.

Lance su primer plugin esta misma tarde.

Código fuente PHP completo. Actualizaciones de por vida. El sistema de Hooks. Ejemplos reales en producción para copiar. Pago único de $199 por la Licencia Extendida (redistribución comercial de plugins + uso SaaS).

Comprar Licencia Extendida — $199 Probar la demo en vivo