REST API Connection

You can’t use a relative path for the redirect_uri

Ok I thought it could have been relative. It’s now sending me back to the callback url with the code query var appended.

I’ve just written this laravel code to test…

if (request()->query('code') && !$infusionsoft->getToken()) {
    $token = serialize($infusionsoft->requestAccessToken(request()->query('code')));
    Cache::store('file')->set('token', $token);
}

Is this a step in the right direction?

Hi brad I just quickly wrote a wrapper class to manage my tokens for the infusionsoft SDK

Is this a good way to manage tokens and re-generating a token? It’s very basic for now and I can run requestAccessToken on the class easy enough but i’m not sure on a good way to refresh an access token as its a bit hard to test when my access token isn’t expired

class IS
{

    public $token;
    public $client;

    public function __construct() {

      $this->client = new Infusionsoft([
        'clientId' => env('INFUSIONSOFT_CLIENT_ID'),
        'clientSecret' => env('INFUSIONSOFT_CLIENT_SECRET'),
        'redirectUri' => route('infusionsoft.callback')
      ]);

      if (!Cache::store('file')->has('infusionsoft_access_token'))
        return false;

      $this->token = unserialize(Cache::store('file')->get('infusionsoft_access_token'));
      $this->client->setToken($this->token);

      if ($this->client->isTokenExpired()) 
        $this->refreshAccessToken();

      return false;

    }

    public function __call($method, $args) {
      if (!method_exists($this->client, $method)) 
        return false;
        
      return call_user_func_array([
        $this->client,
        $method
      ], $args);
    }

    private function refreshAccessToken() {
      $token = $this->client->refreshAccessToken([
        'grant_type' => 'refresh_token',
        'refresh_token' => $this->token->refreshToken
      ]);

      $this->token = serialize($token);
      
      Cache::store('file')->put('infusionsoft_access_token', $this->token, 43800);
    }


}

It’s been like a week and nobody has replied.

Can I get some support on this?

I was hoping someone with some php experience was going to jump in. Maybe @John_Borelli?

Hey, @Richard_Sanderson,

I don’t traditionally favor caching or sessions for token management. Not that you can’t do it but it just introduces more variables that can go wrong. The most consistent uptime I’ve seen and used has been to use a DB table and run a refresh cycle every hour on a CRON job. When the service runs, it checks the stored time to live and then, if four hours or less remain, attempt a refresh. This gives at least three opportunities to succeed should an issue be present that prevents it from passing the first time. Then, on success, update the table with the new set of access/refresh tokens, the date/time and the time to live because when the refresh succeeds, the previous set becomes invalidated. You would then only need an endpoint (or create an object) to manage retrieval of the access token from the database when needed. My video discusses this approach and covers some of the pit falls to look out for:

@John_Borelli

I have moved to storing the token in my DB but when I write a task to refresh the token it works fine. But if I try again to refresh the token then it will error. Here’s my error code:

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

Here’s my code to refresh the token:

$token = $client->refreshAccessToken([
  'grant_type' => 'refresh_token',
  'refresh_token' => $token->refreshToken
]);
Config::set('infusionsoft_access_token', serialize($token));

This refresh code worth the first time around but once I retry it after the first refresh it will just error every time. Am I doing something wrong?

@Richard_Sanderson,

I would only expect to see that if you didn’t replace the DB access/refresh tokens with the new ones you get back because once you request the new set the ones in the DB are invalid and must be replaced by the new.

@John_Borelli I think I may have figured it out… I’ve setup a cronjob now to refresh the token which seems to be working.

I am using the PHP SDK and I am not too familiar with the API just yet. I am creating a test contact using the following code:

$res = $is->contacts()->create([
  'duplicate_option' => 'Email',
  'email_addresses' => [
    'email' => 'testtesttest@gmail.com',
    'field' => 'EMAIL1'
  ],
  'custom_fields' => [
    'serial' => 'ABCABCABC',
    'machine' => 'TEST'
  ],
  'family_name' => 'Test',
  'given_name' => 'Tester',
  'middle_name' => 'Testing',
  'notes' => 'TEST',
  'source_type' => 'TEST'
], true);

Would this be a good way to createOrUpdate a contact? When I just tried this I got a “Input could not be converted to a valid request” response

That’s good but I’d probably also create a text log with the return values from the refresh request so if an error happens on the api server it will be reported back as a text string and then you will have a copy of the message.

Yea this was the error:

400 Bad Request response: {"message":"Input could not be converted to a valid request"}

Any ideas how I can get it to work?

Also does the response for creating a contact return the contact ID? I cannot see it in the documentation for the create contact response. This is so I can apply a tag to it after

The good news is that the authentication is working because you wouldn’t have gotten that message if it were not.

So that message almost always refers to a malformed JSON payload. I would recopy the sample json from the interactive iodocs, hard code some test values and then get that to work. Then you can insert variable data where appropriate.

Yea you are right, email_addresses needed to be an array.

If i parse “addresses” will it append to the address array or just over-ride the current array for a contact already in the system?

I haven’t tried with REST so while I know that the sdk will allow dups by email with some functions I’m not certain if the REST implementation would…you’d have to run a test to find out for sure :wink:

Hi @Richard_Sanderson, although the REST endpoint takes an array of email addresses, they each map directly to individual fields on the contact via the field property. If you provide an email address and specify field=EMAIL1 for example, it will override whatever value is in the primary email field.

Ok thanks Nicholas.

Also @John_Borelli I am looking at the PHP SDK on Github. Is there a Infusionsoft::contacts()->update() method? I guess if you did Infusionsoft::contacts()->create() it returns the customer information then but is there a way to update contact information using the SDK?

I can find the update medhod for non REST but the restful class does not have update. https://github.com/infusionsoft/infusionsoft-php/blob/master/src/Infusionsoft/Api/Rest/ContactService.php

How would you then go to update the contact? On the docs it looks like you parse the data to /contacts/{contactId} but I can’t see the functionality in the PHP SDK… would it be something like Infusionsoft::contacts()->update($id, $data)

… I’m just trying to append some data to the notes field. So i’m thinking that if I do an updateOrCreate it will return the contact information then I can append some data to the field. Also would \r\n be treated as a newline if added into notes?

4 days and no reply?

I thought I was going crazy after spending hours digging through the REST API docs trying to figure out how I auth requests for internal use only. After reading this thread I’m thoroughly disappointed. The fact that there isn’t a way to use a form of basic auth for internal non-UI based applications (our api > infusionsoft) is crazy. OAuth is completely unnecessary for this use case and only adds unnecessary complexity and burden on the part of third party developers trying to access their own data.

@jfx, for a consumer attempting to access their own data we have a mechanism in Account Central to generate a the required Access Token and Refresh Token, rather than needing to walk the full process by hand. Additionally, we are currently preparing additional enhancements to that functionality to provide them without even needing to set up a separate Developer Account.

As far as use goes, it really is as simple as making a call, and if it fails with a 401 NOT AUTHORIZED, hitting the /token endpoint with the Refresh Token to update it, then retying the call.