ictinnovations / php-crm-connectors
Framework-agnostic PHP library of 21 CRM writeback connectors (Zoho, Pipedrive, Salesforce, Dynamics 365, SugarCRM, SuiteCRM, Freshsales, Copper, Capsule and more) behind one contract.
Package info
github.com/ictinnovations/php-crm-connectors
pkg:composer/ictinnovations/php-crm-connectors
Requires
- php: >=7.4
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^9.5 || ^10 || ^11
README
One contract, 21 CRM connectors. A framework-agnostic PHP library for pushing contacts and call/campaign outcomes into the CRMs your customers actually use — Zoho, Pipedrive, Salesforce, Dynamics 365, SugarCRM, SuiteCRM, Freshsales, Copper, Capsule, ActiveCampaign, Close, Keap, Zendesk Sell, Monday, Streak, Vtiger, Apptivo, Agile, Creatio, Less Annoying, and YetiForce.
Every connector implements the same interface, so calling code never changes when you add or switch a CRM:
use ICTInnovations\CrmConnectors\ConnectorFactory; $crm = ConnectorFactory::make('zoho', [ 'client_id' => getenv('ZOHO_CLIENT_ID'), 'client_secret' => getenv('ZOHO_CLIENT_SECRET'), 'refresh_token' => getenv('ZOHO_REFRESH_TOKEN'), 'module' => 'Leads', 'disposition_map' => ['Interested' => 'Qualified', 'Sale' => 'Won'], ]); $result = $crm->run([ 'phone' => '+1 (202) 555-0147', 'first_name' => 'Jane', 'last_name' => 'Doe', 'email' => 'jane@example.com', 'campaign_name' => 'Summer Outreach', 'disposition' => 'Interested', // mapped -> 'Qualified' via disposition_map 'disposition_crm' => 'Qualified', 'duration' => 73, 'history_comments'=> 'Asked for a callback next week.', 'time_connect' => time(), ]); // => ['remote_id' => '3652...', 'remote_module' => 'Leads'] (upserted + note + call activity)
run() finds the contact (by remote_id, then phone, then email), creates it if missing, applies the disposition, and attaches a note + a call activity — all through each CRM's native API.
What each connector gives you
The full contract (drive a CRM directly if you don't need the campaign orchestration):
$crm->authenticate(); $id = $crm->findContactByPhone('12025550147') ?? $crm->findContactByEmail('jane@example.com'); $id = $id ?? $crm->createContact(['first_name'=>'Jane','last_name'=>'Doe','phone'=>'...','email'=>'...']); $crm->updateContact($id, [/* CRM-native fields */]); $crm->createNote($id, ['subject'=>'Call', 'content'=>'...']); $crm->createActivity($id, ['subject'=>'Call', 'duration'=>73, 'time_connect'=>time()]);
Install
composer require ictinnovations/php-crm-connectors
Requires PHP ≥ 7.4 with ext-curl and ext-json. No framework required — works standalone, in Laravel, Symfony, or any app.
Design
- Pluggable token cache. OAuth connectors cache access tokens via a
TokenStore—InMemoryTokenStore(default) orFileTokenStoreship in the box; implement the interface for Redis/DB. - Pluggable logging. Inject a
CallableLogger(or wrap PSR-3); defaults toNullLogger. - No hidden I/O. Every HTTP call goes through one
http()seam — trivial to mock in tests (seetests/ZohoFlowTest.php). - Disposition mapping from a plain
disposition_mapconfig array, per connector.
use ICTInnovations\CrmConnectors\Support\{FileTokenStore, CallableLogger}; $crm = ConnectorFactory::make('pipedrive', $config, new FileTokenStore('/var/cache/crm-tokens.json'), new CallableLogger(fn($lvl,$msg) => error_log("[$lvl] $msg")));
Connectors
ConnectorFactory::available() returns them all. Short name → CRM:
| Short name | CRM | Auth |
|---|---|---|
zoho |
Zoho CRM | OAuth2 refresh token |
pipedrive |
Pipedrive | API token |
salesforce |
Salesforce | OAuth2 |
dynamics365 |
Microsoft Dynamics 365 | OAuth2 |
sugarcrm / suitecrm |
SugarCRM / SuiteCRM | OAuth2 password |
freshsales |
Freshsales | API key |
copper |
Copper | API key |
capsule |
Capsule | bearer token |
activecampaign |
ActiveCampaign | API key |
close |
Close | API key |
keap |
Keap (Infusionsoft) | OAuth2 / PAT |
zendesksell |
Zendesk Sell | bearer token |
monday |
monday.com | API token |
streak |
Streak | API key |
vtiger |
Vtiger | access key |
apptivo |
Apptivo | API key |
agile |
Agile CRM | API key |
creatio |
Creatio | OAuth2 |
lessannoying |
Less Annoying CRM | API token |
yetiforce |
YetiForce | token |
Each connector's config fields are declared in its form() method — see the class under src/Connector/.
Payload shape
run() accepts a partial payload and fills the rest; see docs/PAYLOAD.md for every key.
Testing
composer install
vendor/bin/phpunit # factory, base, token store, and a mocked Zoho end-to-end flow
Connectors are tested by overriding the single http() seam — no live CRM needed.
Provenance & credits
Extracted and generalized from the CRM integration layer of ICTContact (28 CRM modules in production), by ICT Innovations / ICT Vision. Author: Tahir Almas.
MIT licensed — see LICENSE. Contributions welcome; see docs/PORTING.md to add a CRM.