User's UUID from integer ID

How are you supposed to get the UUID for a user? It seems there is no way to request it; at best you sometimes just get it stuffed in other parts of the response depending upon certain circumstances. Other times, you just get the old integer ID. Is there any way to either force the API to respond with a user’s UUID or to convert the integer ID to a UUID?

I’ve not seen an instance where users have UUIDs, at least not the User objects. A quick query against the API tells me the following objects use IDs as listed below:

Users: Integer ID
Membership: UUID
Campaign: Integer ID
Benefit: Integer ID
Pledge Event: Composite ID
Goal: Integer ID

I’ve also no reason to believe that even the Integer and Composite ID are not unique IDs for that object within the Patreon database.

Yes, sorry, I guess I meant the membership UUID. I thought the membership UUID was just the UUID representation of a user ID.

As far as I can tell, the membership UUID represents a given users relationship to a campaign, be it follower, active_patron, or something else.

As for getting it, I could probably help you with that but I’d need to know which API package/language you’re using and what your start point is (campaign, user, or posts).

I use the API directly. My issue is that people can sign into my app with OAuth without being a Patron, in which case they’re not a member, and they don’t have a membership UUID. I also implement a sync function to reload their membership data from time to time, but if they signed up without being a Patreon then I don’t have their UUID to refresh their data, which means it is impossible to resync a user’s membership data who wasn’t a patron when they first signed up but then become one later.

So if they sign into your app without being a patron then you just need to fetch the user identity information and get their User ID.

You could then have your sync function work off the identity fetch call rather than the membership fetch call, which is what I do for my app (largely so I didn’t have to fuss with multiple API call types). If you request the memberships relationship of the user identity it’ll either return empty or return whatever is relevant to your campaign (if you didn’t request additional scopes) or whatever is relevant to the scopes you did request.

Alternatively, when you refresh your membership data, you could request the user relationship as part of that call and then compare the user ID returned from that against the user ID you got when they first logged in.

The Patreon API doesn’t state it in the docs, but since it’s a standard JSON API implementation, you can request relations of the object you’re calling against in the same call. The API won’t return it in the neatest format, but it does return it in a format that clearly states relations between objects.

Edit: Fixed scope to relationship as appropriate

You’re talking about v2 right? I don’t think I can get the subscriber’s tier in the identity call. I have to call /members/<uuid>?include=currently_entitled_tiers separately for that, for which I need their membership UUID. If I could somehow get it from the identity call that would be very nice.

I am indeed talking about v2. Getting entitled tiers via the identity call means you need to include both memberships and memberships.currently_entitled_tiers, which would look something like the below:

/identity?include=memberships,memberships.currently_entitled_tiers&fields...

After that it’s just a matter of picking the fields you need.

My current test environment which I was using to figure out the API in order to update my PHP API fork builds this monstrosity:

'https://www.patreon.com/api/oauth2/v2/identity?include=memberships,memberships.campaign,memberships.campaign.benefits,memberships.campaign.goals,memberships.currently_entitled_tiers,memberships.pledge_history&fields' .urlencode('[user]'). '=can_see_nsfw,email,first_name,full_name,hide_pledges,image_url,is_email_verified,last_name,thumb_url,url,vanity&fields' .urlencode('[member]'). '=campaign_lifetime_support_cents,currently_entitled_amount_cents,is_follower,last_charge_date,last_charge_status,lifetime_support_cents,next_charge_date,patron_status,pledge_cadence,pledge_relationship_start,will_pay_amount_cents&fields' .urlencode('[campaign]'). '=is_monthly&fields' .urlencode('[tier]'). '=amount_cents,discord_role_ids,published,remaining,requires_shipping,title,unpublished_at,url,user_limit'

I will see if I can make a better solution with this information. Thank you!

On another topic, I store the user’s token and refresh token when they connect their account, but I understand the token will expire after some time and then I will have to use the refresh flow. Is there any way to easily test this? I don’t want to keep waiting 30 days to code a working refresh solution!

I don’t know what language you’re using, but in my PHP app I have the following:

	public function refreshPatreonTokens($patron) {
		$now = new \DateTime("now");
		if ($patron->getExpires() < $now) {
			$creator = $patron->getCreator();
			$poa = new POA($creator->getClientId(), $creator->getClientSecret());
			$tokens = $poa->refresh_token($patron->getRefreshToken());
			$patron->setAccessToken($tokens['access_token']);
			$patron->setRefreshToken($tokens['refresh_token']);
			$patron->setExpires(new \DateTime('+'.$tokens['expires_in'].' seconds'));
		}
	}

Whenever you update the tokens they return the expires_in as a number of seconds, so I just toss it in to the database table after converting it to whatever the DateTime is that many seconds in the future. Oh, POA is my shorthandle for calling the Patreon/OAuth class.

And then I just call this function before any other API stuff. You could go a step further and just include a similar function at the start of any of your API call functions and then you’d not need this in the background.

https://docs.patreon.com/#get-api-oauth2-v2-members-id

This particular call with which you request a member’s info for a campaign, should give you the uuid as the id

This can be requested directly, or could be requested as an include as part of another call (per GraphQL format).