emailfunnelai/sdk-php

Official PHP SDK for the Email Funnel AI integration API.

Maintainers

Package info

github.com/EmailFunnelAI/sdk-php

Homepage

Issues

pkg:composer/emailfunnelai/sdk-php

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

dev-main 2026-07-22 07:58 UTC

This package is auto-updated.

Last update: 2026-07-22 08:28:05 UTC


README

Official PHP client for the Email Funnel AI integration API. Connect with your project key and secret, then call typed, resource-oriented methods — no manual URLs, headers, or JSON.

  • PHP 8.1+
  • Zero third-party dependencies (uses ext-curl)
  • Fluent, discoverable API with full endpoint coverage

Installation

composer require emailfunnelai/sdk

Quick start

use EmailFunnelAi\Sdk\Client;

$client = Client::connect(
    projectKey: 'pk_your_project_key',
    projectSecret: 'sk_your_secret_key',
);
// The base URL defaults to https://app.emailfunnel.ai.
// Pass baseUrl: '...' only for staging, self-hosting, or local development.

// 1. Confirm your credentials
$client->validate();

// 2. Get or create a list
$list = $client->lists()->create('Newsletter signups');

// 3. Sync a contact into it
$client->contacts()
    ->sync([
        'email' => 'jane@example.com',
        'first_name' => 'Jane',
        'source_type' => 'custom_saas',
    ])
    ->toList($list['id']);

Usage

Every group is reached from the client and reads as resource → verb.

Contacts

// Single contact
$client->contacts()->sync(['email' => 'jane@example.com', 'source_type' => 'app'])->toList($listId);

// Bulk (up to 500; the server queues automatically above 100 rows)
$client->contacts()->bulk([
    ['email' => 'a@example.com', 'source_type' => 'import'],
    ['email' => 'b@example.com', 'source_type' => 'import'],
], sourceType: 'import')->toList($listId);

// Real-time webhook event
$client->contacts()->webhook('user.created', ['email' => 'jane@example.com'])->toList($listId);

Lists

$client->lists()->all();
$client->lists()->create('My leads', 'Optional description');
$client->lists()->find($listId);

Bindings

$client->bindings()->all();
$client->bindings()->create('custom_crm', $listId, ['sync_enabled' => true]);
$client->bindings()->find($bindingId);
$client->bindings()->update($bindingId, ['sync_enabled' => false]);
$client->bindings()->delete($bindingId);
$client->bindings()->status($bindingId, 'completed', errorsCount: 0);

Field mappings

$client->fieldMappings()->config('custom_crm');
$client->fieldMappings()->forBinding($bindingId)->get();
$client->fieldMappings()->forBinding($bindingId)->update(['email' => 'email', 'first_name' => 'fname']);
$client->fieldMappings()->forBinding($bindingId)->reset();

Auto-tagging

$client->autoTagging()->rules('custom_crm');
$client->autoTagging()->preview('custom_crm', ['email' => 'jane@example.com', 'plan' => 'enterprise']);

Analytics

$client->analytics()->dashboard();
$client->analytics()->heatmap(['range' => 60, 'email_type' => 'all']);
$client->analytics()->funnels();
$client->analytics()->campaigns();
$client->analytics()->forms();

SSO

$client->sso()->generate('owner@example.com'); // signed login URL
$client->sso()->teamMembers();

Responses & errors

Successful calls return the unwrapped data payload as an array. Any error response raises a typed exception:

use EmailFunnelAi\Sdk\Exceptions\ApiException;
use EmailFunnelAi\Sdk\Exceptions\TransportException;

try {
    $client->contacts()->sync(['email' => 'invalid'])->toList($listId);
} catch (ApiException $e) {
    $e->status;     // 422
    $e->errorType;  // "validation_error"
    $e->messages;   // ['contact.email' => ['The email field is required.']]
    $e->retryAfter; // set on 429 rate limits
} catch (TransportException $e) {
    // network / timeout failure (no HTTP response)
}

Both extend EmailFunnelAi\Sdk\Exceptions\EmailFunnelException, so you can catch that to handle any SDK failure.

Branch on errorType for specific conditions — e.g. a contact list that has been deactivated rejects new members with a 409 list_inactive:

try {
    $client->contacts()->sync($contact)->toList($listId);
} catch (ApiException $e) {
    if ($e->errorType === 'list_inactive') {
        // The target list is inactive — reactivate it or pick another list.
    }
}

Common errorType values

errorType Status Meaning
invalid_credentials 401 Missing/invalid project key or secret
inactive_project 403 The connected project is inactive
validation_error 422 Request body failed validation (messages set)
invalid_email / suppressed 422 Email is undeliverable or suppressed
list_inactive 409 Target contact list is inactive and rejects new members
rate_limit_exceeded 429 1000 req/hour cap hit (retryAfter set)
sync_failed 500 Unexpected sync failure

Custom transport

The client uses cURL by default. Inject any EmailFunnelAi\Sdk\Http\HttpClient implementation (e.g. to route through a PSR-18 client or add logging):

$client = Client::connect($base, $key, $secret, http: new MyHttpClient());

Testing

composer install
composer test

Tests mock HTTP and never touch the network. A coverage test asserts the SDK exposes every documented endpoint.

License

MIT © Email Funnel AI