Git Product home page Git Product logo

infusionsoft-php's Introduction

Infusionsoft PHP SDK

Total Downloads Latest Stable Version

Version Notes

This version implements RESTful endpoints, a new version of Guzzle, and a restructured request handler.

As of version 1.6, PHP 7+ is required.

Breaking Change

With the Guzzle 7 upgrade, there was a refactor on the request function name in Infusionsoft\Http\ClientInterface. If you created a custom HttpClient, you'll need to update to use the new function name of call

If you use the Contacts, Orders or Products services, there are now two different classes handling each service - one for REST, one for XML-RPC. This version of the SDK will load the REST class by default. If you still need the XML-RPC class, pass 'xml' as an argument when requesting the object: $infusionsoft->orders('xml')'

Kudos to toddstoker and mattmerrill for their contributions to this release.

Install

Using the composer CLI:

composer require infusionsoft/php-sdk

Or manually add it to your composer.json:

{
    "require": {
        "infusionsoft/php-sdk": "1.6.*"
    }
}

Authentication

Currently Keap supports two types of authentication for our APIs: the OAuth2 Access Code Grant and API Keys.
Developers of third-party integrations should always use our OAuth2 authentication, but developers building integrations for a single tenant may find the use of API Keys much simpler.

OAuth2 Access Code Grant

The client ID and secret are the key and secret for your OAuth2 application found at the Infusionsoft Developers website.

if(empty(session_id();)) session_start();

require_once 'vendor/autoload.php';

$infusionsoft = new \Infusionsoft\Infusionsoft(array(
	'clientId'     => 'XXXXXXXXXXXXXXXXXXXXXXXX',
	'clientSecret' => 'XXXXXXXXXX',
	'redirectUri'  => 'http://example.com/',
));

// If the serialized token is available in the session storage, we tell the SDK
// to use that token for subsequent requests.
if (isset($_SESSION['token'])) {
	$infusionsoft->setToken(unserialize($_SESSION['token']));
}

// If we are returning from Infusionsoft we need to exchange the code for an
// access token.
if (isset($_GET['code']) and !$infusionsoft->getToken()) {
	$_SESSION['token'] = serialize($infusionsoft->requestAccessToken($_GET['code']));
}

if ($infusionsoft->getToken()) {
	// Save the serialized token to the current session for subsequent requests
	$_SESSION['token'] = serialize($infusionsoft->getToken());

	// MAKE INFUSIONSOFT REQUEST
} else {
	echo '<a href="' . $infusionsoft->getAuthorizationUrl() . '">Click here to authorize</a>';
}

API Keys

API Keys are a "password" for your data in an application and should always be treated like a dangerous secret.

In our UI you will find an API Settings screen which divides API Keys into two distinct categories:

  • Personal Access Tokens, which are scoped to your own user account and can only see and manipulate the data you have access to.
  • Service Account Keys, which can only be authorized by an Administrator and have full access to the data stored in the application.

For additional information on how to authorize and use PATs and SAKs please see our developer documentation.

require_once 'vendor/autoload.php';

$infusionsoft = new \Infusionsoft\Infusionsoft(array(
  'apikey' => $APIKeyRetrievedFromCredentialStorage,
));

// MAKE INFUSIONSOFT REQUEST

Making XML-RPC Requests

require_once 'vendor/autoload.php';

//
// Setup your Infusionsoft object here, then set your token either via the request or from storage
// As of v1.3 contacts defaults to rest
$infusionsoft->setToken($myTokenObject);

$infusionsoft->contacts('xml')->add(array('FirstName' => 'John', 'LastName' => 'Doe'));

Making REST Requests

The PHP SDK is setup to allow easy access to REST endpoints. In general, a single result is returned as a Class representing that object, and multiple objects are returned as an Infusionsoft Collection, which is simply a wrapper around an array of results making them easier to manage.

The standard REST operations are mapped to a series of simple functions. We'll use the Tasks service for our examples, but the operations below work on all documented Infusionsoft REST services.

To retrieve all tasks:

$tasks = $infusionsoft->tasks()->all();

To retrieve a single task:

$task = $infusionsoft->tasks()->find($taskId);

To query only completed tasks:

$tasks = $infusionsoft->tasks()->where('status', 'completed')->get();

You can chain where() as many times as you'd like, or you can pass an array:

$tasks = $infusionsoft->tasks()->where(['status' => 'completed', 'user_id' => '45'])->get();

To create a task:

$task = $infusionsoft->tasks()->create([
   'title' => 'My First Task',
   'description' => 'Better get it done!'
]);

Then update that task:

$task->title = 'A better task title';
$task->save();

And finally, to delete the task:

$task->delete();

Several REST services have a /sync endpoint, which we provide a helper method for:

$tasks = $infusionsoft->tasks()->sync($syncId);

This returns a list of tasks created or updated since the sync ID was last generated.

require_once 'vendor/autoload.php';

//
// Setup your Infusionsoft object here, then set your token either via the request or from storage
//
$infusionsoft->setToken($myTokenObject);

$infusionsoft->tasks()->find('1');

Dates

DateTime objects are used instead of a DateTime string where the date(time) is a parameter in the method.

$datetime = new \DateTime('now',new \DateTimeZone('America/New_York'));

Debugging

To enable debugging of requests and responses, you need to set the debug flag to try by using:

$infusionsoft->setDebug(true);

Once enabled, logs will by default be written to an array that can be accessed by:

$infusionsoft->getLogs();

You can utilize the powerful logging plugin built into Guzzle by using one of the available adapters. For example, to use the Monolog writer to write to a file:

use Monolog\Handler\StreamHandler;
use Monolog\Logger;

$logger = new Logger('client');
$logger->pushHandler(new StreamHandler('infusionsoft.log'));

$infusionsoft->setHttpLogAdapter($logger);

Testing

$ phpunit

Laravel Framework Support

Laravel < 5.5

In config/app.php, register the service provider

Infusionsoft\FrameworkSupport\Laravel\InfusionsoftServiceProvider::class,

Register the Facade (optional)

'Infusionsoft'       => Infusionsoft\FrameworkSupport\Laravel\InfusionsoftFacade::class

Laravel >= 5.5

In Laravel 5.5, package auto-discovery was added. The service provider and facade will be detected for you. Continue by publishing the vendor assets and adding your env variables.

Publish the config

php artisan vendor:publish --provider="Infusionsoft\FrameworkSupport\Laravel\InfusionsoftServiceProvider"

Set your env variables

INFUSIONSOFT_CLIENT_ID=xxxxxxxx
INFUSIONSOFT_SECRET=xxxxxxxx
INFUSIONSOFT_REDIRECT_URL=http://localhost/auth/callback

Access Infusionsoft from the Facade or Binding

 $data = Infusionsoft::data()->query("Contact",1000,0,['Id' => '123'],['Id','FirstName','LastName','Email'], 'Id', false);

 $data = app('infusionsoft')->data()->query("Contact",1000,0,['Id' => '123'],['Id','FirstName','LastName','Email'], 'Id', false);

Lumen Service Provider

In bootstrap/app.php, register the service provider

$app->register(Infusionsoft\FrameworkSupport\Lumen\InfusionsoftServiceProvider::class);

Set your env variables (make sure you're loading your env file in app.php)

INFUSIONSOFT_CLIENT_ID=xxxxxxxx
INFUSIONSOFT_SECRET=xxxxxxxx
INFUSIONSOFT_REDIRECT_URL=http://localhost/auth/callback

Access Infusionsoft from the Binding

 $data = app('infusionsoft')->data()->query("Contact",1000,0,['Id' => '123'],['Id','FirstName','LastName','Email'], 'Id', false);

SDK Development

You can install the Composer dependencies without installing Composer:

docker-compose run composer

You can access the samples by spinning up the Docker container for the Composer dependencies:

docker-compose up -d

Tests can be executed without installing PHP in the host environment (while the main container is running):

docker exec -it infusionsoft-php /var/www/html/vendor/bin/phpunit tests

If using Docker for Windows, please see .env for additional details.

Contributing

Please see CONTRIBUTING for details.

License

The MIT License (MIT). Please see License File for more information.

infusionsoft-php's People

Contributors

ajohnson6494 avatar andrewryno avatar bbooth avatar dependabot[bot] avatar gguenther24 avatar greggor88 avatar igorsantos07 avatar iugo-robert avatar jeremiahmarks avatar jgourley avatar koctbijib avatar kressaty avatar mattmerrill avatar mfadul24 avatar mfairch avatar micfai avatar mickaelsavafi-keap avatar miky9585 avatar nova4005 avatar phillbooth avatar ribdot avatar roenschg avatar romzombie avatar ryanlholt avatar sdanyalk avatar skeemer avatar skylord123 avatar toddstoker avatar ultimater avatar upwebdesign avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

infusionsoft-php's Issues

Error while sending request

I got this error message while trying to request an API call

exception 'fXmlRpc\Exception\HttpException' with message 'An HTTP error occurred'

My code looks like this:

try {
            $this->infWrapper->data()->getUserInfo();
        } catch (TokenExpiredException $t) {
            $this->_setInfToken($this->infSettings);

            $this->_refreshAccessToken();
            $this->_saveNewToken($this->infWrapper->getToken());
        }

it happens when the refresh token is expired. But when I try to catch the HttpException, with this code

try {
            $this->infWrapper->data()->getUserInfo();
        } catch (TokenExpiredException $t) {
            $this->_setInfToken($this->infSettings);

            $this->_refreshAccessToken();
            $this->_saveNewToken($this->infWrapper->getToken());
        } catch (\Infusionsoft\Http\HttpException $h) {
            $this->_setInfToken($this->infSettings);

            $this->_refreshAccessToken();
            $this->_saveNewToken($this->infWrapper->getToken());
        }

it works again. Can you explain why is it like that?

Message: [curl] 6: Couldn't resolve host 'api.infusionsoft.com' [url] https://api.infusionsoft.com/token

It seems alot of issues are being caused due the api.infusionsoft.com being unavailable Any advise on this?

Type: Guzzle\Http\Exception\CurlException

Message: [curl] 6: Couldn't resolve host 'api.infusionsoft.com' [url] https://api.infusionsoft.com/token

Filename: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php

Line Number: 338

Backtrace:

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php
Line: 279
Function: isCurlException

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php
Line: 244
Function: processResponse

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php
Line: 227
Function: processMessages

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php
Line: 211
Function: executeHandles

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php
Line: 105
Function: perform

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiProxy.php
Line: 91
Function: send

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php
Line: 282
Function: send

File: /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php
Line: 198
Function: send

File: /home/zae/app/vendor/infusionsoft/php-sdk/src/Infusionsoft/Http/GuzzleClient.php
Line: 35
Function: send

File: /home/zae/app/vendor/infusionsoft/php-sdk/src/Infusionsoft/Infusionsoft.php
Line: 266
Function: request

File: /home/zae/app/_a/libraries/Infusionsoft.php
Line: 101
Function: refreshAccessToken

File: /home/zae/app/_a/libraries/Infusionsoft.php
Line: 73
Function: _refreshTokenWithAction

File: /home/zae/app/_a/libraries/Infusionsoft.php
Line: 49
Function: _execute

File: /home/zae/app/_a/controllers/admin/Forms/View.php
Line: 24
Function: getWebform

File: /home/zae/app/public/index.php
Line: 309
Function: require_once 

Session token not found

Hi! I'm quite new with Infusionsoft API. I'm using Laravel and I'm following this tutorial. I just started with Exchange the Code for an Access Token. And I just realized that there's no session named token by debugging using $request->session('token') after redirect back to my site and all I got is Laravel session. My code looks like this

public function key(Request $request)
    {
        // Setup a new Infusionsoft SDK object
        $infusionsoft = new Infusionsoft(array(
            'clientId'     => getenv('INFUSIONSOFT_CLIENT_ID'),
            'clientSecret' => getenv('INFUSIONSOFT_CLIENT_SECRET'),
            'redirectUri'  => getenv('INFUSIONSOFT_REDIRECT_URL'),
        ));

        // If the serialized token is already available in the session storage,
        // we tell the SDK to use that token for subsequent requests, rather
        // than try and retrieve another one.
        if ($request->has('token')) {
            $infusionsoft->setToken(unserialize($request->session('token')));
        }

        // If we are returning from Infusionsoft we need to exchange the code
        // for an access token.
        if ($request->has('token') and !$infusionsoft->getToken()) {
            $infusionsoft->requestAccessToken($request->get('code'));
        }

        dd($infusionsoft);
    }

Is there any fix for this?

Token expired time

I have following code to call Infusionsoft API

    public function call($method, $call, $args = array(), $count = 0)
    {
        if ($count > 10) {
            log_message('error', '10 failed tries made to: Infusionsoft->' . $method . '->' . $call . '() passing the arguments:<br/>' . print_r($args, true));
            throw new \Infusionsoft\Http\HttpException('10 failed tries made to: Infusionsoft->' . $method . '->' . $call . '() passing the arguments:<br/>' . print_r($args, true));
        }

        $this->setSettings();  // Get serialized token from database and store it to $this->infSettings

        $this->infusionsoft = new Infusionsoft(array(
            'clientId' => getenv('INFUSIONSOFT_CLIENT_ID'),
            'clientSecret' => getenv('INFUSIONSOFT_CLIENT_SECRET'),
            'redirectUri' => getenv('INFUSIONSOFT_REDIRECT_URL'),
        ));

        $token = $this->setInfToken($this->infSettings);  // Set infusionsoft token object and return the token object

        if ($token->getEndOfLife() < time()) { // Imitating Infusionsoft request() method
            $token = $this->infusionsoft->refreshAccessToken();
            log_message('error', 'Token has been refreshed <br/><pre>' . print_r($token, true) . '</pre>');

            $this->saveNewToken($token);  // Save new token to database
            log_message('error', 'New token saved');
        }

        // Try API call
        try {
            $data = $this->infusionsoft->{$method}()->{$call}(...$args);
        } catch (TokenExpiredException $ex) {
            log_message('debug', 'Token expired, refreshing token <br/><pre>' . print_r($token, true) . '</pre>');

            $token = $this->infusionsoft->refreshAccessToken();
            log_message('debug', 'Token has been refreshed <br/><pre>' . print_r($token, true) . '</pre>');

            $this->saveNewToken($token);

            $data = $this->call($method, $call, $args, ++$count);
        }

        return $data;
    }

with this code, when token expired, it will return "401 unauthorized" error. It seems the token didn't get refreshed although I've added token expired condition. So, I'm trying to re-authorize and Infusionsoft auth server return data with following endOfLife:

[endOfLife] => 1446495397 // date('d-m-Y H:i:s', 1446495397) = 02-11-2015 20:16:37

and then, I'm trying to set it to Infusionsoft token object and debug it. Surprisingly, the token object endOfLife become:

[endOfLife] => 2892962011 // date('d-m-Y H:i:s', 2892962011) = 29-07-1925 02:05:15

That's why my token expiration checking didn't work at all. So I check this SDK, I found that on Token class constructor, it add time to the endOfLife element

if (isset($data['expires_in']))
{
    $this->setEndOfLife(time() + $data['expires_in']);
    unset($data['expires_in']);
}

Is it intended or what? Because it won't meet the token expired condition.

Send email not working


$infusionsoft->emails->sendEmail($contactIds,$fromEmail,"~Contact.Email~", "", "", "HTML", $title, $content, "", "");```

I am getting an exception what is wrong with my code

exception 'fXmlRpc\Exception\ResponseException' with message 'No method matching arguments: java.lang.String, [Ljava.lang.Object;, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String

Refresh Token being refused

After doing some troubleshooting with this issue, I traced the issue to the layout of the refresh function.

The OAuth spec says the client_id and secret should be in POST params. By moving them there, I got the function to work.

public function refreshAccessToken()
{
    $params = array(
        'client_id' => $this->clientId,
        'client_secret' => $this->clientSecret,
        'grant_type'    => 'refresh_token',
        'refresh_token' => $this->getToken()->getRefreshToken(),
    );
    $client = $this->getHttpClient();

    $tokenInfo = $client->request($this->tokenUri, $params, array(), 'POST');

    $this->setToken(new Token($tokenInfo));

    return $this->getToken();
}

This only worked for my case so I don't know if this is a real issue or just my circumstances.

validateCreditCard No method matching arguments..

Looks like it's an issue from APIs end, I'm getting the same error from IO docs simulator.

No method matching arguments: java.lang.String, java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String, java.lang.String

http://d.pr/i/w9Fv

$infusionsoft->invoices->validateCreditCard('Visa', $cid, 'xxxxxxxxxxxxxxxx', '10', '2015', 'xxx');`

gives

Uncaught exception 'Infusionsoft\InfusionsoftException' with message 'No method matching arguments: java.lang.String, java.lang.Integer, java.lang.String, java.lang.String, java.lang.String, java.lang.String' in /Applications/MAMP/htdocs/infusion_sdk/vendor/infusionsoft/php-sdk/src/Infusionsoft/Infusionsoft.php:359

DataService query method does not work

To make a query via the data service I'm having to resort to manually generating a request via the Infusionsoft class instead of relying on the DataService class. Reason being there are non-optional parameters defined in the query method on line 73 of DataService.php which when specified and passed to the request method of the client, returns an XML-RPC error saying "No method matching arguments".

Either this library demands PHP have warnings for unspecified method parameters turned off (not the best practice) or it's just plain broken. Please fix.

Tests to validate request xml payloads

I got few unexpected method exceptions when doing API calls (issue #5 ) and since there were no tests to validate actual xml payload, I implemented my own.

https://github.com/sahanh/infusionsoft-php/tree/develop

Here's how an actual service call is validated

class InvoiceServiceTest extends \ServiceTest
{

    public function testCreateBlankOrder()
    {
        $this->ifs->invoices->createBlankOrder(111, 'hello world', new \DateTime('2014-08-08'), 2, 3);
        $this->verifyCall('InvoiceService.createBlankOrder');
    }
}

image

By default the final request will be validated against a preset xml file under tests/Infusionsoft/Api/fixtures, but it can be overridden.

I'm using aspect mock and it requires php 5.4. Thought of sharing it with you guys.

Thanks.

Client error response [status code] 400 [reason phrase] Bad Request

When it's time to refresh the token I receive the error below. I know sometimes the there is a connection error with infusionsoft so i retry a few times but it does not help. can you advise on what I'm missing here?

exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 400 [reason phrase] Bad Request [url] https://api.infusionsoft.com/token' in /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/BadResponseException.php:43 Stack trace: #0 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(145): Guzzle\Http\Exception\BadResponseException::factory(Object(Guzzle\Http\Message\EntityEnclosingRequest), Object(Guzzle\Http\Message\Response)) #1 [internal function]: Guzzle\Http\Message\Request::onRequestError(Object(Guzzle\Common\Event), 'request.error', Object(Symfony\Component\EventDispatcher\EventDispatcher)) #2 /home/zae/app/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php(164): call_user_func(Array, Object(Guzzle\Common\Event), 'request.error', Object(Symfony\Component\EventDispatcher\EventDispatcher)) #3 /home/zae/app/vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.php(53): Symfony\Component\EventDispatcher\EventDispatcher->doDispatch(Array, 'request.error', Object(Guzzle\Common\Event)) #4 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(589): Symfony\Component\EventDispatcher\EventDispatcher->dispatch('request.error', Object(Guzzle\Common\Event)) #5 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(378): Guzzle\Http\Message\Request->processResponse(Array) #6 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php(49): Guzzle\Http\Message\Request->setState('complete', Array) #7 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(286): Guzzle\Http\Message\EntityEnclosingRequest->setState('complete', Array) #8 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(244): Guzzle\Http\Curl\CurlMulti->processResponse(Object(Guzzle\Http\Message\EntityEnclosingRequest), Object(Guzzle\Http\Curl\CurlHandle), Array) #9 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(227): Guzzle\Http\Curl\CurlMulti->processMessages() #10 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(211): Guzzle\Http\Curl\CurlMulti->executeHandles() #11 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(105): Guzzle\Http\Curl\CurlMulti->perform() #12 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiProxy.php(91): Guzzle\Http\Curl\CurlMulti->send() #13 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Client.php(282): Guzzle\Http\Curl\CurlMultiProxy->send() #14 /home/zae/app/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(198): Guzzle\Http\Client->send(Object(Guzzle\Http\Message\EntityEnclosingRequest)) #15 /home/zae/app/vendor/infusionsoft/php-sdk/src/Infusionsoft/Http/GuzzleClient.php(35): Guzzle\Http\Message\Request->send() #16 /home/zae/app/vendor/infusionsoft/php-sdk/src/Infusionsoft/Infusionsoft.php(266): Infusionsoft\Http\GuzzleClient->request('https://api.inf...', Array, Array, 'POST') #17 /home/zae/app/_a/libraries/Infusionsoft.php(78): Infusionsoft\Infusionsoft->refreshAccessToken() #18 /home/zae/app/_a/libraries/Infusionsoft.php(88): Infusionsoft::_refreshTokenWithAction('webForms', 'getMap', Array) #19 /home/zae/app/_a/libraries/Infusionsoft.php(88): Infusionsoft::_refreshTokenWithAction('webForms', 'getMap', Array) #20 /home/zae/app/_a/libraries/Infusionsoft.php(88): Infusionsoft::_refreshTokenWithAction('webForms', 'getMap', Array) #21 /home/zae/app/_a/libraries/Infusionsoft.php(50): Infusionsoft::_refreshTokenWithAction('webForms', 'getMap', Array) #22 /home/zae/app/_a/libraries/Infusionsoft.php(35): Infusionsoft::_execute('webForms', 'getMap') #23 /home/zae/app/_a/controllers/admin/Sync/Index.php(39): Infusionsoft::getWebforms() #24 [internal function]: Index->select() #25 /home/zae/app/_s/core/Zae.php(514): call_user_func_array(Array, Array) #26 /home/zae/app/public/index.php(309): require_once('/home/zae/app...') #27 {main}

Custom Drop down fields updated through the API do not update on campaign builder decision diamonds

Suppose you have a custom drop down field with the values: ValueA,ValueB,ValueC.

You then use this field in a decision diamond in the campaign builder, and select the different values for different sequences.

Using the API to update the custom fields (using updateCustomField), you change the values of this custom field to: First,Second,Third.

Now if you go into the campaign with the decision diamond, it will still show the old values as valid options, and NOT show the new values. The decision diamond will also be broken, as no one will be able to attain these values.

However, if you just go to the admin settings and save the custom field values without changing anything, and then go back into the campaign, it will show that the old values (ValueA,ValueB,Valuec) are invalid, and allow you to choose the new values.

This makes using the updateCustomField a big deterrent, because of the obvious complications this causes. I have tested this a few times and the result is consistent.

Google App Engine support

I'm developing an app to run on Google App Engine and ran into a snag. It doesn't have the CURL extension. Guzzle doesn't need it in the newer versions. Can we get it upgraded?

Companies being loaded into Contacts

I am running some tests using the 1.0.0 release.
We have Companies and Contacts that need to be loaded. Everything is pushed up in batches to reduce the amount of updates. The problem is that when adding the Company they are loading into the contacts. When we go and try to update the entry, it is failing because it can't find the entity.

Here is the code for the insert or update. $crm_method is set by whether $crm_company_id is null or not :

$dataObject = $infusionsoft->data();
if($crm_method == 'insert'){
    $crm_company_id = $dataObject->add('Company',   $values);
    $sql = "update company set crm_infusionsoft_company_id = '" . $crm_company_id . "' where company_id = '" . $company_id . "' ";
    sql_query_write($sql);
} else {
    $crm_company_id = $row['crm_infusionsoft_company_id'];
    $dataObject->update('Company',$crm_company_id,  $values);
}

Here is the error that is being generated when our end tries to update:

PHP Fatal error:  Uncaught exception 'Infusionsoft\Http\HttpException' with message 'exception 'fXmlRpc\Exception\ResponseException' with message '[RecordNotFound]Unable to perform update. Record not found for Id:48872' in /var/www/xyz/models/CRM/lstrojny/fxmlrpc/src/fXmlRpc/Exception/ResponseException.php:33
Stack trace:
#0 /var/www/xyz/models/CRM/lstrojny/fxmlrpc/src/fXmlRpc/Client.php(162): fXmlRpc\Exception\ResponseException::fault(Array)
#1 /var/www/xyz/models/CRM/infusionsoft/php-sdk/src/Infusionsoft/Http/InfusionsoftSerializer.php(28): fXmlRpc\Client->call('DataService.upd...', Array)
#2 /var/www/xyz/models/CRM/infusionsoft/php-sdk/src/Infusionsoft/Infusionsoft.php(384): Infusionsoft\Http\InfusionsoftSerializer->request('https://api.inf...', 'DataService.upd...', Array, Object(Infusionsoft\Http\CurlClient))
#3 /var/www/xyz/models/CRM/infusionsoft/php-sdk/src/Infusionsoft/Api/DataService. in /var/www/xyz/models/CRM/infusionsoft/php-sdk/src/Infusionsoft/Http/InfusionsoftSerializer.php on line 34

AffiliateService HttpException

I am creating a new issue as my other ticket was out of scope with the issue I (and others) am experiencing.

This is my attempt to use Affiliate Program Service (AffiliateProgramService):

Infusionsoft::affiliatePrograms()->getProgramsForAffiliate((int)xxxxx);
Infusionsoft::affiliatePrograms()->getAffiliatePrograms();

This is what I get:

HttpException in InfusionsoftSerializer.php line 34:
exception 'fXmlRpc\Exception\RuntimeException' with message 'Invalid XML. Expected one of "string", "array", "struct", "int", "biginteger", "i8", "i4", "i2", "i1", "boolean", "double", "float", "bigdecimal", "dateTime.iso8601", "dateTime", "base64", "nil", "dom", "#text", got "value" on depth 9 (context: "")' in /vendor/lstrojny/fxmlrpc/src/fXmlRpc/Exception/RuntimeException.php:41

This was referenced to issue Invalid XML error #3 then this issue was reference with fxmlrpc lstrojny/fxmlrpc#36 by which my response was:

Thanks for pointing that out. Your composer.json file is pulling in release "lstrojny/fxmlrpc": "0.8.*", which I assume does not have the fxmlrpc lstrojny/fxmlrpc#36 fix in it. It looks like it failed: lstrojny/fxmlrpc@0.8.3...master Am I reading this correctly?

I am stuck on what to do because infusionsoft-php owns the dependency and I am not keen on forking the project. Is this issue something Infusionsoft can address or not? Any sort of response will be helpful.

Respectfully

refreshAccessToken always returns Invalid refresh token

Hey guys,

every time I try to refresh the access token the api returns a 400 Bad Request, with the error Invalid refresh token.

I followed the recommendations here #16 ,but nothing seems to work so far. I serialize the Token before I save it into the session and unserialize before I need it. My code looks like the following:

Infusionsoft::setToken(unserialize($this->session->get('infusionsoft_token')));

if ( is_object(Infusionsoft::getToken()) && Infusionsoft::isTokenExpired()) {
   Log::info('[Infusionsoft] Need to refresh token');
   Infusionsoft::refreshAccessToken();
}

Response

GuzzleHttp\Exception\ClientException: Client error: `POST https://api.infusionsoft.com/token` resulted in a `400 Bad Request` response:
{"error":"invalid_grant","error_description":"Invalid refresh token"}

Token

Infusionsoft\Token":4:{s:11:"accessToken";s:24:"access_token";s:12:"refreshToken";s:24:"refresh_token";s:9:"endOfLife";i:1455201501;s:9:"extraInfo";a:2:{s:10:"token_type";s:6:"bearer";s:5:"scope";s:32:"full|somewebsite.com";}}

result of time()

1455234193

Invalid XML error

I often get this kind of issue when using the search module with saved search:
search->getSavedSearchResults

Fatal error: Uncaught exception 'Infusionsoft\InfusionsoftException' with message 'Invalid XML. Expected one of "string", "array", "struct", "int", "biginteger", "i8", "i4", "i2", "i1", "boolean", "double", "float", "bigdecimal", "dateTime.iso8601", "dateTime", "base64", "nil", "dom", "#text", got "value" on depth 9 (context: "")' in \infusionsoft-php\src\Infusionsoft\Infusionsoft.php on line 350

So I am not sure if this is caused by Infusionsoft API or the data that is returned. Is there any way to deal with this? Seems to occur only on special fields. E.g.: I have a saved search on Credit Card report and the error occurs when the field Exp is in the fields return array (which is the expiration date string field).

Access token refreshing

It seems in my reading of the code that I will have to add a try/catch and a loop around every call because of token expiration. Is there a reason the request() function doesn't refresh the access token if it's expired?

vendor/autoload.php

What is vendor/autoload.php supposed to be in the sample?
require_once '../vendor/autoload.php';

CURL <url> Malformed

When using the cURL client i regularly get the following error

Fatal error: Uncaught exception 'Amesplash\Infusionsoft\Http\HttpException' with message 'exception 'Ivory\HttpAdapter\HttpAdapterException' with message 'An error occurred when fetching the URI "/DataService.add" with the adapter "curl" (" malformed").

Sometimes if i retry the query it passes. This is generally caused when using the DataService.add or DataService.Query.

Any advise on this.

node / JS API?

guess this isn't the best place to ask, but i've looked around...
is there a nodeJS or javascript API anywhere?

i guess you don't expose anything client side, is that correct?

Api key?

How can I work with this library having only api key?

Legacy Token Authorization Expiration?

From the docs:

In the past, the Infusionsoft API has relied on a simple token based system; while those tokens will remain active until some date in the future, any new implementations will be required to use OAuth for all requests.

As the maintainer of a repository supporting this older method (used by many WordPress users, which only have PHP 5.2), I'd like to know:

  • When will this old token based method be expiring?
  • Will there be an announcement in advance of the expiration, or will you guys just flip the switch?
  • Do you have a PHP 5.2 friendly wrapper for the new iSDK?

Some services work, some don't

I am hoping I can get some answers/suggestions with this issue I am having with the API. For example, I am able to "load" a contact and get contact fields, no problem. I can "search" saved searches from the API, awesome. BUT, when I try to use the "AffiliateService" OR "AffiliateProgramService "methods, an exception is thrown.

Sample call:
$infusionsoft->affiliates()->affPayouts(xxxxx, Carbon::now()->subMonth(), Carbon::now());

Results in:

HttpException in InfusionsoftSerializer.php line 34:

exception 'fXmlRpc\Exception\ResponseException' with message 'No such handler: AffiliateService.affPayouts'

This is the case for ALL AffiliateService methods. There must be something I am not quite understanding, or is the API incomplete? We are supposed to pass dateTime objects into the methods, correct?

It seams as though the handler is named incorrectly...

Thanks for any guidance!

Need to remove $key in Funnel.achieveGoal

Seems there is an issue with the FunnelService > achieveGoal. I am not sure why the $key parameter is there, I don't think it should. I removed it and now it works, however the return always give me errors like eventhough the call has passed:

Error Message: Invalid XML. Expected one of "string", "array", "struct", "int", "biginteger", "i8", "i4", "i2", "i1", "boolean", "double", "float", "bigdecimal", "dateTime.iso8601", "dateTime", "base64", "nil", "dom", "#text", got "value" on depth 9 (context: "")

Syntax error when refreshing token

When trying to refresh the token I keep getting "Parse error: syntax error, unexpected '->' (T_OBJECT_OPERATOR), expecting ')' in vendor\infusionsoft\php-sdk\src\Infusionsoft\Infusionsoft.php on line 371"

$args = array_merge(array('key' => token->getAccessToken()), $args);

Should be

$args = array_merge(array('key' => $token->getAccessToken()), $args);

Wrong Composer Install

In the composer file, "infusionsoft/php-sdk" does not work, but "infusionsoft/php-isdk" does.

Cache support

This is more a suggestion than a issue. I know that guzzle has a cache plugin. It will be great to see caching implemented in this sdk to speed up calls, as some of the call to isoft can be really time consuming and API has a rate limit. Thanks!

Getting fatal GuzzleHttpClient error when authenticating

hello, I'm running through the docs on https://github.com/infusionsoft/infusionsoft-php#authentication and I instantly get a

Fatal error: Declaration of Infusionsoft\Http\GuzzleHttpClient::request() must be compatible with GuzzleHttp\ClientInterface::request($method, $uri = NULL, array $options = Array) in /var/www/scotchbox2.dev/public/infusionsoft/vendor/infusionsoft/php-sdk/src/Infusionsoft/Http/GuzzleHttpClient.php on line 15

using scotchbox which runs PHP 5.6.10-1+deb.sury.org~trusty+1

SubscriptionPlan missing # of Cycles field in the API

When working with a Subscription Plan via the app, there is a field for # of Cycles that is inaccessible via the API. This needs to be supported for being able to fully integrate with Infusionsoft via the API in any app that is offering remote creation of products that want to use Subscriptions w/ an expiration date.

Error using PHP API..

Hi,

I'm wondering where is the file 'vendor/autoload.php;' on the SDK. I've tried downloading the .zip file but it was not included.

Alternatively, I did include the files like this on my CodeIgniter Views (I'm sure what I'm doing):

require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Infusionsoft.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/InfusionsoftException.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Token.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/TokenExpiredException.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Http/CurlClient.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Http/ClientInterface.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Http/GuzzleClient.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Http/HttpException.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Http/SerializerInterface.php';
require_once APPPATH.'libraries/infusionsoft2/src/Infusionsoft/Http/InfusionsoftSerializer.php';

but its says

Fatal error: Class 'fXmlRpc\Transport\CurlTransport' not found in /srv/users/serverpilot/apps/test/public/application/libraries/infusionsoft2/src/Infusionsoft/Http/CurlClient.php on line 7

I also tried finding the class CurlTransport, but I think it is not existing..

Any help,

Thanks,

Getting uncaught exception on requestAccessToken

so if I run the sample code (with what I assume to be proper credentials (as when I change them I get an error "Unable to create access token." on the https://signin.infusionsoft.com/app/oauth/authorize site)),
I get a consistent exception thrown as follows.

I have created a sandbox account (and tried connecting with a production account as well) and I can't figure out what's going on here.

For clarity, this is when I click on the link to the getAuthorizationUrl, sign into my infusion sandbox account, and then the exception is thrown after I'm redirected to the proper url. I see two get parameters passed back from the login (?scope=full|tv265.infusionsoft.com&code=) where code is a 24 character alphanumeric string.

I've tried catching the exception and seeing if the token was still getting set, but alas it was not.

Any help at all is appreciated!

   Infusionsoft\Http\HttpException: exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response
   [status code] 400
   [reason phrase] Bad Request
   [url] https://api.infusionsoft.com/token' in /MYSITE/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/BadResponseException.php:43

Full error:

      Fatal error: Uncaught exception 'Infusionsoft\Http\HttpException' with message 'exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message ' in EDITEDvendor/infusionsoft/php-sdk/src/Infusionsoft/Http/GuzzleClient.php on line 59 Infusionsoft\Http\HttpException: exception 'Guzzle\Http\Exception\ClientErrorResponseException' with message 'Client error response [status code] 400 [reason phrase] Bad Request [url] https://api.infusionsoft.com/token' in EDITED/vendor/guzzle/guzzle/src/Guzzle/Http/Exception/BadResponseException.php:43 Stack trace: #0 EDITED/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(145): Guzzle\Http\Exception\BadResponseException::factory(Object(Guzzle\Http\Message\EntityEnclosingRequest), Object(Guzzle\Http\Message\Response)) #1 [internal function]: Guzzle\Http\Message\Request::onRequestError(Object(Guzzle\Common\Event), 'request.error', Object(Symfony\Component\EventDispatcher\EventDispatcher)) #2 EDITED/vendor/symfony/event-dispatcher/EventDispatcher.php(164): call_user_func(Array, Object(Guzzle\Common\Event), 'request.error', Object(Symfony\Component\EventDispatcher\EventDispatcher)) #3 EDITED/vendor/symfony/event-dispatcher/EventDispatcher.php(53): Symfony\Component\EventDispatcher\EventDispatcher->doDispatch(Array, 'request.error', Object(Guzzle\Common\Event)) #4 /EDITED/content/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(589): Symfony\Component\EventDispatcher\EventDispatcher->dispatch('request.error', Object(Guzzle\Common\Event)) #5 /EDITED/vendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(378): Guzzle\Http\Message\Request->processResponse(Array) #6 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Message/EntityEnclosingRequest.php(49): Guzzle\Http\Message\Request->setState('complete', Array) #7 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(286): Guzzle\Http\Message\EntityEnclosingRequest->setState('complete', Array) #8 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(244): Guzzle\Http\Curl\CurlMulti->processResponse(Object(Guzzle\Http\Message\EntityEnclosingRequest), Object(Guzzle\Http\Curl\CurlHandle), Array) #9 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(227): Guzzle\Http\Curl\CurlMulti->processMessages() #10 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(211): Guzzle\Http\Curl\CurlMulti->executeHandles() #11 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMulti.php(105): Guzzle\Http\Curl\CurlMulti->perform() #12 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Curl/CurlMultiProxy.php(91): Guzzle\Http\Curl\CurlMulti->send() #13 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Client.php(282): Guzzle\Http\Curl\CurlMultiProxy->send() #14 EDITEDvendor/guzzle/guzzle/src/Guzzle/Http/Message/Request.php(198): Guzzle\Http\Client->send(Object(Guzzle\Http\Message\EntityEnclosingRequest)) #15 EDITEDvendor/infusionsoft/php-sdk/src/Infusionsoft/Http/GuzzleClient.php(53): Guzzle\Http\Message\Request->send() #16 EDITEDvendor/infusionsoft/php-sdk/src/Infusionsoft/Infusionsoft.php(229): Infusionsoft\Http\GuzzleClient->request('https://api.inf...', Array, Array, 'POST') #17 EDITEDControllers/manage_controller.php(119): Infusionsoft\Infusionsoft->requestAccessToken('xemv93sx32u22c3...') #18 EDITEDLibrary/Route.php(56): manage_controller->infusionSoft() #19 EDITEDLibrary/Route.php(35): loadController(Array) #20 EDITEDloader.php(31): require('/var/smartsite/...') #21 EDITEDindex.php(19): require('/var/smartsite/...') #22 {main} in EDITEDvendor/infusionsoft/php-sdk/src/Infusionsoft/Http/GuzzleClient.php on line 59 Call Stack: 0.0000 240848 1. {main}() EDITEDindex.php:0 0.0001 241368 2. require('EDITEDloader.php') EDITEDindex.php:19 0.0017 322464 3. require('EDITEDLibrary/Route.php') EDITEDloader.php:31 0.0017 323176 4. loadController() EDITEDLibrary/Route.php:35 0.0030 374696 5. manage_controller->infusionSoft() EDITEDLibrary/Route.php:56 0.0034 421464 6. Infusionsoft\Infusionsoft->requestAccessToken() EDITEDControllers/manage_controller.php:119 0.0036 433792 7. Infusionsoft\Http\GuzzleClient->request() EDITEDvendor/infusionsoft/php-sdk/src/Infusionsoft/Infusionsoft.php:229

With the following code

      $infusionsoft = new \Infusionsoft\Infusionsoft(array(
            'clientId'     => APPLICATION_KEY
            'clientSecret' => APPLICATION_CLIENT_SECRET,
            'redirectUri'  => $redirectUri,
        ));


        // If we are returning from Infusionsoft we need to exchange the code for an
        // access token.
        if (isset($_GET['code']) and !$infusionsoft->getToken()) {
            $infusionsoft->requestAccessToken($_GET['code']);
        }

    if ($infusionsoft->getToken()) {
            die('THIS CODE HAS NEVER RUN');
        } else {
            echo '<a href="' . $infusionsoft->getAuthorizationUrl() . '">Click here to authorize</a>';
        }

README file instructions for Lumen do not work

Specifically this line:

$data = app('infusionsoft')->query("Contact",1000,0,['Id' => '123'],['Id','FirstName','LastName','Email']);

I get "undefined method 'query'" when attempting this.

Not able to update custom drop down field values with data()->update method

I am trying to update the values of a custom drop down field using the API, but regardless of what I try to pass, nothing changes.

$infusionsoft->data()->update('DataFormField',$recordID,array('values'=>$newValues));

Where $recordID is an integer, and $newValues is a string with \r\n separated values (as IFS API returns when queried).

When I run this call, it returns successful (returning the recordID), but the values do not change. I tried then using $newValues as an array instead of string and same result. Tried searching online but can't seem to find any documentation on how to update the custom fields online through the API.

How to get token without clicking link

Hi.
I need to access api but without any user involved to this process. It's absolutely not acceptable to force users to click some external links, so I need the way to generate token automatically.
Is it possible?

Authenticated User Info

I'm adding Infusionsoft to a social login plugin of mine and i want to retrieve their basic information such as first name, last name and user id. Now when a user has completed the OAuth flow i do not see a way to retrieve the this info. Any advise?

Call to a member function getRefreshToken() on a non-object

My code :
$infusionsoft = new InfusionsoftInfusionsoft(array(
'clientId' => 'CLIENT_ID',
'clientSecret' => 'CLIENT_SECRET',
'redirectUri' => 'REDIRECT_URL',
));

// retrieve the existing token object from storage
$infusionsoft->setToken($yourStoredToken);

$infusionsoft->refreshAccessToken(); // this function create error.

refreshAccessToken function is following:

public function refreshAccessToken()
{
$headers = array(
'Authorization' => 'Basic ' . base64_encode($this->clientId . ':' . $this->clientSecret),
);

    $params = array(
        'grant_type'    => 'refresh_token',
        'refresh_token' => $this->getToken()->getRefreshToken(),
    );

    $client = $this->getHttpClient();

    $tokenInfo = $client->request($this->tokenUri, $params, $headers, 'POST');

    $this->setToken(new Token($tokenInfo));

    return $this->getToken();
}

Error is Following :

Call to a member function getRefreshToken() on a non-object

Build fail

When trying to follow the steps it fails. Also the build status on on the project page says error.

Here is what I get

composer require infusionsoft/php-sdk
Using version ^1.1 for infusionsoft/php-sdk
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

Problem 1
- The requested package infusionsoft/php-sdk No version set (parsed as 1.0.0) could not be found.

Potential causes:

Read https://getcomposer.org/doc/articles/troubleshooting.md for further common problems.

Installation failed, reverting ./composer.json to its original content.

Exception handler misreporting InfusionsoftTokenExpired

ITE exceptions are not properly coming through, and in general the Guzzle client is throwing exceptions to early in the chain that are not being properly caught. Consider disabling Guzzle exceptions for HTTP codes, and ensure that token expired exception is properly fired.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.