emailfunnelai / sdk-php
Official PHP SDK for the Email Funnel AI integration API.
Requires
- php: ^8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- phpunit/phpunit: ^10.5
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