Complete Pipedrive API client for PHP

Overview

Complete Pipedrive API client for PHP

Latest Stable Version Build Status Total Downloads

Contribute by referral code / link

This won't take much time. You could use my referral code or link to get up to 45 days completely free of charge. Just sign up using this link or add the code to the billing section:

pdp-devio

Consider donating

Do you like this package? Did you find it useful? Donate and support its development.

Donate


This package provides a complete framework agnostic Pipedrive CRM API client library for PHP. It includes all the resources listed on Pipedrive's documentation.

IMPORTANT: If you are using Laravel >= 5.8 make sure your version is > 2.1.0.

Feel free to drop me a message at [email protected] or tweet me at @IsraelOrtuno.

Quick start using API token (read below for OAuth)

$token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxx';
$pipedrive = new Pipedrive($token);

// Easily access a Pipedrive resource and its values
$organization = $pipedrive->organizations->find(1);
var_dump($organization->getData());

// Also simple to update any Pipedrive resource value
$organization = $pipedrive->organizations->update(1, ['name' => 'Big Code']);
var_dump($organization->getData());

// Keep reading this documentation to find out more.

For a deeper knowledge of how to use this package, follow this index:

Important

Versions 1.x do not include OAuth support, update to version 2.x to use this feature.

Installation

You can install the package via composer require command:

composer require devio/pipedrive

Or simply add it to your composer.json dependences and run composer update:

"require": {
    "devio/pipedrive": "^2.0"
}

Usage

Create the Pipedrive instance

Devio\Pipedrive\Pipedrive class acts as Manager and will be responsible of resolving the different API resources available. Pipedrive supports two different authentication methods: via API token (for manual integrations) and with OAuth (for public and private apps). You can read more about it on the official documentation, here: https://pipedrive.readme.io/docs/core-api-concepts-authentication

Using API token

$token = 'PipedriveTokenHere';
$pipedrive = new Pipedrive($token);

NOTE: Consider storing this object into a global variable.

Using OAuth

To understand how the OAuth flow works, please read the documentation first.
You can find it here: https://pipedrive.readme.io/docs/marketplace-oauth-authorization

You will first need to create an app and retrieve client_id and client_secret. Please, read the official documentation to learn how to do that.
You can find all you need here: https://pipedrive.readme.io/docs/marketplace-creating-a-proper-app

Once you have your client_id, client_secret, and redirect_url, you can instantiate the class like this:

$pipedrive = Pipedrive::OAuth([
    'clientId' => '<your-client-id>',
    'clientSecret' => '<your-client-secret>',
    'redirectUrl' => '<your-redirect-url>',
    'storage' => new PipedriveTokenIO() // This is your implementation of the PipedriveTokenStorage interface (example below)
]);

The class will automatically handle the redirect to the authentication server and refresh token requests.

The only thing you need to provide is your own implementation of the PipedriveTokenStorage interface.

The purpose of this class is to read and write a PipedriveToken object, containing access_token, refresh_token, and expiresAt, giving you the ability to handle this information as you prefer (for example storing these properties in your preferred way).

Here's an example of how it can be implemented:

class PipedriveTokenIO implements \Devio\Pipedrive\PipedriveTokenStorage
{
    public function setToken(\Devio\Pipedrive\PipedriveToken $token) {
        $_SESSION['token'] = serialize($token); // or encrypt and store in the db, or anything else...
    }

    public function getToken() { // Returns a PipedriveToken instance 
        return isset($_SESSION['token']) ? unserialize($_SESSION['token']) : null;
    }
}

In this simple example, the PipedriveToken is simply stored and retrieved from the session. Which means that once the session expires, the user will be redirected to the authentication page.

You might want to store this object inside the database. Storing the whole object serialized could be the fastest way to do that, but you can also retrieve access token, refresh token, and the expiration time individually using the methods getAccessToken, getRefreshToken, and expiresAt. Like this:

public function setToken(\Devio\Pipedrive\PipedriveToken $token) {
    $token->getAccessToken(); // save it individually
    $token->getRefreshToken(); // save it individually
    $token->expiresAt(); // save it individually
}

Similarly, the object can be instantiated like so:

$token = new \Devio\Pipedrive\PipedriveToken([
    'accessToken' => 'xxxxx', // read it individually from the db
    'refreshToken' => 'xxxxx', // read it individually from the db
    'expiresAt' => 'xxxxx', // read it individually from the db
]);

Handling the callback

In the callback (the url you specified as redirectUrl), you should call the authorize method on the $pipedrive object, like so:

if(!empty($_GET['code'])) {
    $pipedrive->authorize($_GET['code']);
}

This will exchange the authorization code for the first access token, and store it using the setToken method you provided.

Resolve a Pipedrive API Resource

Once we have our Pipedrive instance, we are able to resolve any Pipedrive API Resource in many ways.

First you could do it calling the make() method:

// Organizations
$organizations = $pipedrive->make('organizations');
// Persons
$persons = $pipedrive->make('persons');
// ...

It also intercepts the magic method __get so we could do:

// Deals
$deals = $pipedrive->deals;
// Activities
$activities = $pipedrive->activities;
// ...

And just in case you prefer __call, you can use it, too:

// EmailMessages
$emailMessages = $pipedrive->emailMessages();
// GlobalMessages
$globalMessages = $pipedrive->globalMessages();
// ...

They are 3 different ways of doing the same thing, pick the one you like the most. It will automatically set the studly case version of the asked resource, so it will work with emailMessages, EmailMessages, email_messages...

IMPORTANT: Navigate to the src/Resources directory to find out all the resources available.

Performing a resource call

Available methods

All resources have various methods for performing the different API requests. Please, navigate to the resource class you would like to work with to find out all the methods available. Every method is documented and can also be found at Pipedrive API Docs page.

Every resource extends from Devio\Pipedrive\Resources\Basics\Resource where the most common methods are defined. Some of them are disabled for the resources that do not include them. Do not forget to check out the Traits included and some resources use, they define some other common calls to avoid code duplication.

Performing the Request

After resolved the resource we want to use, we are able to perform an API request. At this point, we only have to execute the endpoint we would like to access:

$organizations = $pipedrive->organizations->all();
//
$pipedrive->persons->update(1, ['name' => 'Israel Ortuno']);

Any of these methods will perform a synchronous request to the Pipedrive API.

Handling the response

Every Pipedrive API endpoint gives a response and this response is converted to a Devio\Pipedrive\Http\Response object to handle it:

$response = $pipedrive->organizations->all();

$organizations = $response->getData();

Response methods

The Response class has many methods available for accessing the response data:

isSuccess()

Check if the server responded the request was successful.

getContent()

Will provide the raw response provided by the Pipedrive API. Useful if you need specific control.

getData()

Get the response main data object which will include the information about the endpoint we are calling.

getAdditionalData()

Some responses include an additional data object with some extra information. Fetch this object with this method.

getStatusCode()

Get the response status code.

getHeaders()

Get the response headers.

Available resources

Every Resource logic is located at the src/Resources directory. However we'll mention every included resource here:

Resource Methods implemented Notes
Activities 6/6
ActivityFields 1/1
ActivityTypes 5/5
Currencies 1/1
DealFields 25/25
Deals 6/6
EmailMessages 4/4
EmailThreads 6/6
Files 8/8
Filters 6/6
GlobalMessages 2/2
Goals ⚠️ 5/6 Missing goal results method
Notes 5/5
NoteFields 1/1
OrganizationFields 6/6
OrganizationRelationships 5/5
Organizations 18/18
PermissionsSets 6/6
PersonFields 18/20
Persons ⚠️ 18/20 Missing add and delete pictures as getting required fields error.
Pipelines ⚠️ 6/8 Missing deals conversion rates and deals movements
ProductFields 6/6
Products 9/9
PushNotifications 4/4
Recents 1/1
Roles ⚠️ 0/11 Getting unathorized access
SearchResults 2/2
Stages 7/7
UserConnections 1/1
Users ⚠️ 13/20 Getting unathorized access when playing with roles and permissions
UserSettings 1/1

Completed / ⚠️ Pipedrive API errors

The File Resource

The File resource is the only one that works a little bit different than others. While other resources may be intuitively used as most of them just require a plain array of tada, the File resource requires an \SplFileInfo instance to make it work:

$file = new \SplFileInfo('document.pdf');

$pipedrive->files->add([
    'file'   => $file,
    'person_id' => 1,
    // 'deal_id' => 1
]);

Actually, it is pretty simple. Just pass a \SplFileInfo instance to the file key of the options array and specify at least one of the elements it goes related to (deal, person, ...).

Configure and use in Laravel

If you are using Laravel, you could make use of the PipedriveServiceProvider and PipedriveFacade which will make the using of this package much more comfortable:

Service Provider and Facade

Include the PipedriveServiceProvider to the providers array in config/app.php and register the Laravel Facade.

'providers' => [
  ...
  Devio\Pipedrive\PipedriveServiceProvider::class,
  ...
],
'alias' => [
    ...
    'Pipedrive' => Devio\Pipedrive\PipedriveFacade::class,
    ...
]

The service configuration

Laravel includes a configuration file for storing external services information at config/services.php. We have to set up our Pipedrive token at that file like this:

'pipedrive' => [
    'token' => 'the pipedrive token'
]

Of course, as many other config parameters, you could store the token at your .env file or environment variable and fetch it using dotenv:

'pipedrive' => [
    'token' => env('PIPEDRIVE_TOKEN')
]

Using it

You could use it using the Laravel facade PipedriveFacade that we have previously loaded:

$organizations = Pipedrive::organizations()->all();
//
Pipedrive::persons()->add(['name' => 'John Doe']);

Also, resolve it out of the service container:

$pipedrive = app()->make('pipedrive');

Or even inject it wherever you may need using the Devio\Pipedrive\Pipedrive signature.

Contribute

Feel free to contribute via PR.

Comments
  • OAuth support for (Guzzle >= 6)

    OAuth support for (Guzzle >= 6)

    Fixed previous PR.

    Pipedrive OAuth can be instantiated like this

    $pipedrive = Pipedrive::OAuth([
        'clientId' => 'xxxxx',
        'clientSecret' => 'xxxxx',
        'redirectUrl' => 'xxxxx',
        'storageClass' => new PipedriveTokenIO()
    ]);
    

    PipedriveTokenIO is the user's own implementation of the PipedriveTokenStorage interface, with the two setToken and getToken methods.

    setToken accepts an instance of PipedriveToken, which has these attributes

    protected $access_token;
    protected $expires_at; // expires AT, not IN (calculated as time() + expires_in, coming from Pipedrive
    protected $refresh_token;
    

    PipedriveToken silently takes care of refreshing the token when needed, and updates it through the setToken method.

    PipedriveClient checks if the token is valid. If it's not (or it's not set yet), it calls $pipedrive->OAuthRedirect();. On the callback page, you can call $pipedrive->authorize($_GET['code']); to get the first token (also automatically stored through the setToken method).

    TODO:

    • comments
    • support for Guzzle < 6 (which should be quick to implement)
    • better handling of the redirect (?)

    Here's a basic, not-so-great implementation of PipedriveTokenStorage, just to get the idea:

    class PipedriveTokenIO implements \Devio\Pipedrive\PipedriveTokenStorage
    {
        public function setToken(\Devio\Pipedrive\PipedriveToken $token)
        {
            $_SESSION['token'] = serialize($token); // or encrypt and store in the db, or anything else...
        }
    
        public function getToken()
        {
            return isset($_SESSION['token']) ? unserialize($_SESSION['token']) : null;
        }
    }
    
    opened by daniti 13
  • guzzle client error

    guzzle client error

    GuzzleHttp\Exception\RequestException

    cURL error 60: SSL certificate problem: unable to get local issuer certificate (see http://curl.haxx.se/libcurl/c/libcurl-errors.html)

    I get that error when i try to test out your code. Please update your GuzzleClient to allow user to setup their cacert.pem file location to fix this issue.

    opened by midcore-nam 12
  • File upload

    File upload

    I can't get the file upload working. I'm not sure it's an issue with the library, maybe I'm doing something wrong. If so, I'm sorry ;)

    public function uploadFile($dealId, \SplFileInfo $file)
    {
         $upload = $this->pipedrive->files->add([
            'file' => $file,
            'deal_id' => $dealId
        ]);
    }
    

    This throws a PipedriveException: 'No files were provided with the request.'.

    What's going wrong?

    bug 
    opened by stephanvierkant 9
  • Symfony support

    Symfony support

    I'm using Symfony and I think this repo would be easy to use with Symfony, but there are some small problems with it right now:

    • The studly_case function doesn't exist. (https://github.com/IsraelOrtuno/pipedrive/blob/master/src/Pipedrive.php#L54)
    • No documentation how to use it w/ Symfony

    Currently, I'm using TTRGroup/pipedrive-api-php, but it just a stub and it has no active maintainer right now.

    opened by stephanvierkant 8
  • Add pagination to ListsActivities

    Add pagination to ListsActivities

    This by default only returns 100 activities. One can improve to 500 activities by including the ["limit"=> 500] param but it will not paginate through additional resources even if they are available via the API. Can pagination be implemented?

    Thanks!

    opened by ampkeegan 7
  • Call to undefined function camel_case()

    Call to undefined function camel_case()

    Hi, thank you a lot for this library 👍 I have started using that, but I am getting error:

    Call to undefined function Devio\Pipedrive\Resources\Basics\camel_case()

    with code: $pipedrive->make('organizations');

    I see You use function camel_case() in:

    src/Resources/Basics/Resource.php:123

    However it is not defined anywhere, maybe it should be defined?

    opened by Zaszczyk 7
  • Product post endpoint expects prices as an array of objects

    Product post endpoint expects prices as an array of objects

    Setting prices to anything other than a string results in the following error:

    'Warning: preg_replace(): Parameter mismatch, pattern is a string while replacement is an array in /vagrant/vendor/devio/pipedrive/src/Builder.php on line 72

    While setting it to a string returns an error from the API:

    exception 'Devio\Pipedrive\Exceptions\PipedriveException' with message 'Prices must be given as array of objects.' in /vagrant/vendor/devio/pipedrive/src/Http/Request.php:85

    opened by casconed 7
  • Add ItemSearches endpoint, deprecate SearchResults

    Add ItemSearches endpoint, deprecate SearchResults

    We'll want to add the property to Pipedrive.php as well, but we can't just yet as it would conflict with #99. But, to be fair, it might already conflict with that PR so oh well. :)

     * @property-read ItemSearches $itemSearches
    

    If you want to do it yourself, awesome. If you want me to do it after you merge the other PRs, just let me know!

    opened by simensen 6
  • retrieve List activities associated with a deal

    retrieve List activities associated with a deal

    Hello, Is there a way to retrieve a list activities associated with a deal like: $pipedrive->deals(7528)->activities->all()->getContent()->data ?

    regards

    opened by noudard 6
  • List updates about a deal

    List updates about a deal

    Hello ! First, thank you for this beautiful work :) However, I do not really understand regarding methods marked as implemented. I want to list all updates about a deal (flow function in pipedrive api) and it doesn't seems to exist. Am I right ? or do I don't understand ?

    thank you

    opened by boudafc 6
  • builder.php line 76 Object of class stdClass could not be converted to string

    builder.php line 76 Object of class stdClass could not be converted to string

    Hello, i find all deal in specific stage and i would like create activity but i receive an error :

    Recoverable fatal error: Object of class stdClass could not be converted to string in .../vendor/devio/pipedrive/src/Builder.php on line 76

    My code is

    
    foreach ($EtapeRelanceSMS as $etape){
        $rotten_days=$pipedrive->stages->find($etape)->getcontent()->data->rotten_days;
        foreach ($pipedrive->deals->all(["stage_id" => $etape ,"status" => "open"])->getContent()->data as $thedeals){
            
            $dateactivity = new datetime($thedeals->update_time);
            $currentdate = new datetime();
           
            if( $currentdate->diff($dateactivity)->format("%a") > $rotten_days ){
                // create new activity 
                
                $pipedrive->activities->add(['type' => 'monsms', 'deal_id' => $thedeals->id, "person_id" => $thedeals->person_id, "note" => $contentSMSpart1 . $thedeals->value ." €". $contentSMSpart2 ,"user_id" => $thedeals->user_id]);
              
                if ($EtapeRelanceSMS['relance'] == $etape){
                    //$pipedrive->deals->update($thedeals->id,["stage_id" => $EtapeRelanceSMS['attente']]);
    
                }
                if ($EtapeRelanceSMS['attente'] == $etape){
                    //$pipedrive->deals->update($thedeals->id,["status" => "lost"]);
                }
                if ($EtapeRelanceSMS['à suivre'] == $etape){
                    //$pipedrive->deals->update($thedeals->id,["status" => "lost"]);
                    
                }
                echo $dateactivity->format("d/m/y"). " ".$currentdate->format("d/m/y") ." ";
                echo ($currentdate->diff($dateactivity)->format("%a") . " ".$rotten_days ." ". $thedeals->id ." ".  $thedeals->title ."<br>" );
            }
            
         };
    
    }
    

    The error is from $pipedrive->activities->add(['type' => 'monsms', 'deal_id' => $thedeals->id, "person_id" => $thedeals->person_id, "note" => $contentSMSpart1 . $thedeals->value ." €". $contentSMSpart2 ,"user_id" => $thedeals->user_id]);

    Best regards

    opened by noudard 5
  • Service Provider :: Wrong Dependency Injection

    Service Provider :: Wrong Dependency Injection

    It seems like PipedriveServiceProvider does not exactly follow the Laravel instructions for creating a provider. Since the register() method should only be used to bind interfaces and the rest should be moved to the boot() method. //This might affect the backward compatibility

    Reference: https://laravel.com/docs/8.x/providers#writing-service-providers cc: @pultho

    
    class PipedriveServiceProvider extends ServiceProvider
    {
        public function register()
        {
            $this->app->booting( function () {
                $loader = \Illuminate\Foundation\AliasLoader::getInstance();
                $loader->alias( 'Pipedrive', 'Devio\Pipedrive\PipedriveFacade' );
            } );
    
            $this->app->singleton(Pipedrive::class, function ($app) {
                $token = $app['config']->get('services.pipedrive.token');
                $uri = $app['config']->get('services.pipedrive.uri') ?: 'https://api.pipedrive.com/v1/';
                $guzzleVersion = $app['config']->get('services.pipedrive.guzzle_version') ?: 6;
    
                if (! $token) {
                    throw new PipedriveException('Pipedrive was not configured in services.php configuration file.');
                }
    ...
    
    opened by walkingCommiter 1
  • Changes on API endpoints in March 2021

    Changes on API endpoints in March 2021

    Pipedrive developers team are going to change some endpoints, among them:

    • [ ] GET /deals/find
    • [ ] GET /persons/find
    • [ ] GET /organizations/find
    • [ ] GET /products/find
    • [x] GET /searchResults
    • [x] GET /searchResults/field

    There's going to have some update to support these new changes?

    opened by LeMajstor 10
Releases(2.15.0)
Owner
Israel Ortuño
Israel Ortuño
A complete anti-cheat to defend the server from malicious users.

Advanced Anti-Cheat vAlpha An Anti-Cheat plugin with various preventions and support for apis ≤ 2.0.0. ?? Features Options that are not checked will s

null 11 Dec 3, 2022
A complete stack for running Symfony 5 into Docker containers using docker-compose tool and with Certbot for the HTTPS certificate.

?? Docker + PHP 7.4 + MySQL8.0 + Nginx + Certbot(HTTPS) + Symfony 5 Boilerplate ?? Edited from https://github.com/ger86/symfony-docker version -> http

null 6 Nov 9, 2022
Laravel Podcast Manager is a complete podcast manager package for Laravel 5.3+ that enables you to manage RSS feeds for your favorite podcasts and listen to the episodes in a seamless UI.

laravelpodcast | A Laravel podcast manager package - v0.0.8 Introduction Laravel Podcast Manager is a complete podcast manager package for Laravel 5.3

Jeremy Kenedy 22 Nov 4, 2022
This package is considered feature-complete, and is now in security-only maintenance mode

laminas-soap This package is considered feature-complete, and is now in security-only maintenance mode, following a decision by the Technical Steering

Laminas Project 46 Dec 18, 2022
This repository aims to build a fairly complete CI/CD example using GitHub workflows and actions.

CI/CD example This repository aims to build a fairly complete CI/CD example using GitHub workflows and actions. Keep in mind that the toolset used in

Robin Ingelbrecht 4 Nov 1, 2022
Magento sample data includes a sample store, complete with more than 250 products

Magento sample data includes a sample store, complete with more than 250 products (about 200 of them are configurable products), categories, promotional price rules, CMS pages, banners, and so on. Sample data uses the Luma theme on the storefront.

Magento 203 Dec 16, 2022
O-CONGO est un projet open source qui donne accès à la liste complète et officielle des toutes les provinces

O-CONGO est un projet open source qui donne accès à la liste complète et officielle des toutes les provinces, villes et communes de la République Démocratique du Congo (RDC), dans un premier temps.

SmirlTech 7 Aug 18, 2022
A complete solution for group projects in organizations that lets you track your work in any scenario. Working in a team is a cumbersome task, ease it using our project management system.

SE-Project-Group24 What is Evolo? Evolo is Dashboard based Project Management System. A complete solution for group projects in organizations that let

Devanshi Savla 2 Oct 7, 2022
A PHP API client for ConvertKit

ConvertKit PHP API Client Introduction This is an API Client for the ConvertKit mailing list service for PHP versions 7.4 and up There are several cli

null 0 Aug 29, 2022
PHP client library for Coveralls API.

php-coveralls PHP client library for Coveralls. Prerequisites PHP 5.5+ for 2.x or 5.3+ for 1.x On GitHub Building on Travis CI, CircleCI, Jenkins or C

null 514 Dec 25, 2022
Enterprise isEven API Client

zonuexe\isEvenApi This package is a modern, high performance, high modularity and strongly static typed enterprise quality API Client of isEven API fo

USAMI Kenta 3 Aug 26, 2021
This document provides the details related to Remittance API. This APIs is used to initiate payment request from Mobile client/others exchange house.

City Bank Remittance API This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. Installation You c

MD ARIFUL HAQUE 2 Oct 2, 2022
A GETTR.com client library written in PHP with Laravel support.

Gettr API Clinet PHP A GETTR.com client library written in PHP with Laravel support. This library uses unofficial publicly accessible API endpoints of

null 10 Dec 13, 2022
SendCloud client for PHP

SendCloud client for PHP Installation composer require guangda/sendcloud Example $mailData = [ 'to'=>'[email protected]', 'subject'=>'test',

Guangda 3 Aug 27, 2021
Bearer client for the PHP programming language

Bearer PHP Client This is the official PHP client for interacting with Bearer.sh. Installation Install the package by running: composer require bearer

Bearer 9 Oct 31, 2022
The most widely used PHP client for RabbitMQ

php-amqplib This library is a pure PHP implementation of the AMQP 0-9-1 protocol. It's been tested against RabbitMQ. The library was used for the PHP

php-amqplib 4.2k Jan 3, 2023
kafka php client

Kafka-php 中文文档 Kafka-php is a pure PHP kafka client that currently supports greater than 0.8.x version of Kafka, this project v0.2.x and v0.1.x are in

Weibo Ad Platform Open Source 1.4k Jan 5, 2023
Artax is an asynchronous HTTP client for PHP based on Amp

Artax is an asynchronous HTTP client for PHP based on Amp. Its API simplifies standards-compliant HTTP resource traversal and RESTful web service consumption without obscuring the underlying protocol. The library manually implements HTTP over TCP sockets; as such it has no dependency on ext/curl.

AMPHP 21 Dec 14, 2022
Grpc go-server php-client

Grpc go-server php-client

凯 1 Jan 24, 2022