My goal was to send along new attributes for a subset of our users, a set of attributes that only existed in our backend. I couldn't assume that all of our subset existed in the third party - there may be legacy users who we needed to update that didn't exist over there. So my first assumption was to try to pull the user from the API. If a record existed then update it, else create a new record with the new field. But customer.io doesn't work that way.
Their RESTful API has four main endpoints: create a customer, update a customer, delete a customer, and track an event. Well, sort of. Create and update literally do the same thing. You send along an optional set of attributes as key/value pairs and it will attach by the identifier and email address, which are both required fields. So as long as I didn't have to worry about overwriting any fields (which was a mild concern at best) I could just iterate through my subset of users, send an update for each record, and either create or update records with the desired field.
Other than that interesting side trek the rest of the client was pretty simple. I used Presto as the backing CURL library, which isn't as popular as Guzzle by a long stretch, but is something that Shutterstock built and loosely maintains. Originally I built the client to be PSR-0 (which is all our app could support at the time) but have recently upgraded to PSR-4. Oh, and I did have fun with the handling of CURLOPT_ options.
To check out the main source you can view the 'official' repo here: shutterstock/customerio-client. It is actually a fork of the original build (jacobemerick/customerio-client). I'm pretty sure that this isn't the best way to handle upstreams with different namespacing and it's a bit of a headache to upkeep. Oh well. It's a little client that was a fun thing to build and I'll probably keep an eye on future changes to the customer.io API for future changes.