Open davidgeowiz opened 2 years ago
The "click here to authorize" link is used to have you log in to infusionsoft and authorize a token which can be saved and used for future api calls. Ideally you'd authorize manually once. In exchange you'll receive an access token and a refresh token. Save these to a database. The access token can be used within the api for upto 24 hours. Once it expires, you'd use the refresh token to generate a fresh access token and another refresh token. This would invalidate the older refresh token. WIth the fresh access token you'd have another 24 hours to use it until it expires then you'd use the newer refresh token to refresh again etc... This process can be continued for long periods of time. Depending on the application, I've went about 2 years or so without issues. Another application sometimes can only work for a few months until there's a problem with the refresh token. This can happen if there's too many database connections, the load balancer reaches its time limit, internet connectivity issues, etc... But when this does happen, it can be helpful to have more than one pair of an access token and a refresh token to keep the application going, and to send a prompt to the devs to re-authenticate another access token and refresh token etc. Once you have a valid access token handy, such as keeping it stored in your database, you can use it for the XMLRPC api or the REST api. Note that the XMLRPC is deprecated such as the table schema. The REST api is newer but lacks a lot of functionality available in the XMLRPC api.
With the older (non-oauth2) legacy access token authentication, there's no authorize step nor having to store stuff to a database. But you'd need oauth2 for using the rest api. The legacy access token works with the XMLRPC though. Note that with the oauth2 (click here to authorize) authentication, it's thought to be more secure. You're also able to manage the application through the keys page: https://keys.developer.keap.com/
There's also other types of access tokens which can be created: https://developer.infusionsoft.com/pat-and-sak/ https://help.infusionsoft.com/help/api-key
Note that what we refer to as infusionsoft (the CRM software) was renamed to Max Classic. While infusionsoft (the company) turned into Keap. There might be a trail, either newer or older, within documentation, but worth keeping in mind.
I have since left the company I was working for when I was using infusionsoft and moved to a different company less than a year ago. There is now a rest api v2. I haven't used this. I've used rest v1 though and the XMLRPC (plus table schema). The REST apis are newer. Anything you can get done using the REST api is encouraged. Otherwise you'd need to fallback to the XMLRPC (deprecated) for further support such as access to the table schema. Refer to https://developer.infusionsoft.com/developer-guide/ (note XMLRPC and the table schema access it provides is deprecated). I don't think there's any timeline for when the XMLRPC will disappear. But it's something Keap wants to eventually phase out, and get people onto the REST apis.
If you run into issues with the api, don't refer to the phone and/or chat support team. They aren't trained with the api. Instead create a ticket: https://developer.infusionsoft.com/support/tickets/ https://developer.infusionsoft.com/support/tickets/create/
(note the login for the above is different from your infusionsoft credentials. it uses its own login system)
But ideally, from as far into the process as you got, it sounds like you just need to authorize, then store the access and refresh tokens into a database. It's also possible to store it elsewhere, etc. You'd also want to make sure your refreshing system works properly. You can use a refresh token as early as you want to get a new access token and refresh token, etc. Just keep in mind OAuth2 should be monitored to make sure you always have a valid access token since you'd need someone to manually authenticate by logging into infusionsoft to get the initial access token and initial refresh token generated if you ever lose access to a valid access token and valid refresh token. It's not enough to store only the access token since it will expire within 24 hours. Refresh tokens are used once to generate new access tokens, then the refresh token is no longer valid and you'd get a new refresh token and new access token which should be stored in your database, and replace the older tokens.
Further reading material: https://developer.infusionsoft.com/tutorials/
TL;DR
"Click here to authorize" is meant to be used once. Once you log in and authorize the application, this will generate an access token and refresh token. This can be done several times and you can have several valid access and refresh tokens floating around. Once your access token reaches its 24 hours limit, have your code use the refresh token to generate a new access token and refresh token and you'd be good for another 24 hours. Use the access token within the api for making api calls.
As far as listing emails, this sounds like a rest v1 only feature: https://developer.keap.com/docs/rest/#operation/listEmailsUsingGET
Hi thank you the above was incredibly helpful and I am able to retrieve a list of emails sent to a user. I have the authentication working and the tokens stored and swapped as needed.
Is the object model and methods listed somewhere? I use the documentation: https://developer.infusionsoft.com/docs/rest/ however I can;t figure out a one-to-one map into the php framework.
I have this working and can iterate through all the emails metadata: $emails = ($infusionsoft->emails()->where(['contact_id' => "$UserID"])->get()); in the $email array that comes back.
I see there are 'id's in there for each message. I have tried different variations of the call I need to retrieve the individual message body. but I can't figure out the call. That particular cal does not return the message body, there is a call listed that does if you have the id but I don;t know how to call it within the provided PHP framework:
https://developer.infusionsoft.com/docs/rest/#operation/getEmailUsingGET
Any help would be appreciated. If there is an object/methods model, or if I could understand the 'philosophy' on how to interpret the API doc to know how its implemented in the PHP framework, or honestly if anyone just knows the construct to get the body of an individual already sent email :-)
This library provides support for around 99% of the documented features for the XMLRPC api (an example of a missing feature through this library is optional sorting key rather than required sorting key on the table schema).
For the REST api v1, that number is much lower. I'm not exactly sure what that number is though.
For the REST api v2, this library provides no built-in support, but you can still use the $infusionsoft>restfulRequest
method as usual for REST api requests, and you'd just specify the REST api url in there.
As far as using the built-in REST api v1 features already coded in this library, without having to go through the restfulRequest method manually, the services provide the base uri for certain features then there's some generic methods such as where() which are available to all rest services in this library by default by extending the RestModel, then blacklisted if a certain service uses a trait which specifies a certain feature isn't available such as CannotWhere. This trait would provide a where() method that would be used instead of the generic where method, which would throw an exception.
When you create your $infusionsoft instance, you'd be using: https://github.com/infusionsoft/infusionsoft-php/blob/master/src/Infusionsoft/Infusionsoft.php
$infusionsoft->emails() would default to the rest api (as long as you don't pass in 'xml' for the xmlrpc api which is completely different, different code, different features, different api) and it will give you the rest api's email service: https://github.com/infusionsoft/infusionsoft-php/blob/master/src/Infusionsoft/Api/Rest/EmailService.php
<?php namespace Infusionsoft\Api\Rest;
use Infusionsoft\Api\Rest\Traits\CannotDelete;
use Infusionsoft\Api\Rest\Traits\CannotModel;
use Infusionsoft\Api\Rest\Traits\CannotSync;
class EmailService extends RestModel
{
use CannotSync, CannotDelete, CannotModel;
public $full_url = 'https://api.infusionsoft.com/crm/rest/v1/emails';
public $return_key = 'emails';
public function send($attributes = [])
{
$response = $this->client->restfulRequest('post', $this->getFullUrl('/queue'), $attributes);
return $response;
}
}
The EmailService extends the RestModel. Note that the full_url is https://api.infusionsoft.com/crm/rest/v1/emails. This uses the REST api v1. Then there's traits which say you cannot delete, cannot model and cannot sync. Thus the generic methods delete(), model(), and sync($id) are overridden to instead throw an exception for the given service, being that they are not supported by the api for the given service, etc.
I'd suggest going through the RestModel to learn more about how the REST v1 works within this library: https://github.com/infusionsoft/infusionsoft-php/blob/master/src/Infusionsoft/Api/Rest/RestModel.php
For example given a $full_url = 'https://api.infusionsoft.com/crm/rest/v1/emails';
If you access ->getFullUrl($id)
it would toss on an extra slash plus the added URI part and return a string pointed at the endpoint you want to work with. Thus you'd wind up with:
'https://api.infusionsoft.com/crm/rest/v1/emails/id'
/**
* Returns the full URL for the query, optionally concatinated with additional URI elements
*
* @return string
*/
public function getFullUrl($additional = null)
{
$url = $this->full_url;
if (substr($url, -1) != '/') {
$url .= '/';
}
if ($additional) {
$additional = ltrim($additional, '/');
}
return $url . $additional;
}
The RestModel makes a lot of usage out the getFullUrl method for accessing various endpoints which all begin with the base uri provided on the service you're working with.
I believe what you're looking for is find:
public function find($id)
{
if (!empty($this->optionalProperities)) {
$data = $this->client->restfulRequest('get',
$this->getFullUrl($id), ['optional_properties' => implode(",", $this->optionalProperities)]);
} else {
$data = $this->client->restfulRequest('get', $this->getFullUrl($id));
}
$this->fill($data);
return $this;
}
Thus you'd wind up with:
$emails = $infusionsoft->emails()->find($id);
Do note that if you run into a service which this library doesn't yet support, such as if you want to use the rest api v2, or if you prefer writing your own code for doing something so you can follow the documentation without spending too much time trying to figure out this library works, or if there's something in the rest api v1 which isn't exactly clear how to do it within this library, you can always do the steps your self.
You'd just refer to:
$infusionsoft>restfulRequest
Note that all the RestModel stuff uses a __construct which gets sent $this from the $infusionsoft instance and stored as $this->client. Thus all the calls in RestModel to $this->client->restfulRequest would actually be calling $infusionsoft>restfulRequest anyways.
It should be relatively easy to design your own class to extend RestModel if you need something. Then toss in $infusionsoft when you create a new instance of the class.
Thus when you do:
$emails = $infusionsoft->emails()->find($id);
This is actually the same as doing:
$emails = new \Infusionsoft\Api\Rest\EmailService($infusionsoft)->find($id);
So if you wrote your own custom service, you could do something like:
namespace App\Services\InfusionsoftRestApi;
use Infusionsoft\Api\Rest\RestModel;
class CustomService extends RestModel
{
// ... your custom implementation
}
Then use it like:
use App\Services\InfusionsoftRestApi\CustomService;
// ...
$result = new CustomService($infusionsoft)->find($id);
There's probably ways to get it yet cleaner. Such as if you extended \Infusionsoft\Infusionsoft. Then tossed in a method for customService. Then when you want to interact with $infusionsoft, it would be an extended version which would include your code. Thus you'd be able to do:
$infusionsoft->customService()->find($id);
But if you do go down that road, I'd almost rather reach for: $infusionsoft>restfulRequest This would have the full power of both REST apis provided you read the REST documentation and build stuff along the way. And perhaps store whatever code you build in this way in your App\Services\InfusionsoftRestApi\CustomService class instead, etc.
TL;DR
You're looking for find.
$emails = $infusionsoft->emails()->find($id);
If you're going by the documentation, in order to find how out to write code which uses this library, a first sign should be if you can find a matching $full_url for any of the services (disregarding child paths) within: https://github.com/infusionsoft/infusionsoft-php/blob/master/src/Infusionsoft/Api/Rest
If you do find a match there's probably a way to use the endpoint you want to use.
I'd suggest going through the RestModel to learn more about how REST works within this library:
https://github.com/infusionsoft/infusionsoft-php/blob/master/src/Infusionsoft/Api/Rest/RestModel.php
Services like the EmailService when you do emails() inherit those methods (e.g. find, with, etc). Also pay attention to the $full_url for the service you're using.
https://github.com/infusionsoft/infusionsoft-php/blob/master/src/Infusionsoft/Api/Rest/EmailService.php
In this case it's:
$full_url = 'https://api.infusionsoft.com/crm/rest/v1/emails';
Methods like "find" use it as a base uri for child endpoints such as /{id}
.
If you go back to the documentation:
https://developer.infusionsoft.com/docs/rest/#operation/getEmailUsingGET
It mentions:
https://api.infusionsoft.com/crm/rest/v1/emails/{id}
Thus this would be a child of the EmailService's full_url.
If you go through the RestModel, you'd eventually find the find
method.
And thus you'd discover how to use this library for the given endpoint:
$emails = $infusionsoft->emails()->find($id);
Hi I have everything installed and working, I have the resthookManager example open. When I run it I get the "Click here to authorize" link. Ultimatly I need to run the List Emails call. I don't understand the login component. We want to add a little view for our users so they can see what emails the system has sent them over time. This is obviously my first working with the Keap API..
If someone could help me understand what I'm missing (I'm sure it simple) that would be hugely appreciated!