Connect Patreon to aMember with Webhooks

In this tutorial, you will learn how to connect Patreon with aMember for free using Webhooks. Once you have established this connection, users who pledge on Patreon will automatically gain access to your products on aMember.
Table of content
- What are we going to build?
- Get your aMember product ID.
- Create aMember API key.
- Set up a webhook server with Cloudflare Workers.
- Add business logic to the Webhook server.
- Add the webhook server to Patreon and test it.
What are we going to build?
We are going to build an App that automates your Patreon and aMember workflow. When a new user pledges on your Patreon, the user will gain access to your aMember membership automatically.
Get your aMember product ID
Go to your aMember Pro admin dashboard, click on the Products menu, and choose Manage Products. From there, you should see a list of your products. Get the product ID to which you want the new Patreon to gain access. The product ID is the number in the first column of your product. If you don't already have a product, click on the New Product button to create one.

Create aMember API key
Go to aMember CP -> Configuration -> Add-ons, and enable api module. If your aMember installation has no "api" module available, you can get it for free in the members area
Once the module is enabled, scroll down and find an admin menu item Remote Api Permissions. Click New Record.
You will see a form to fill - there will be a field for your comment, a generated access key itself, and list of checkboxes describing what system calls is available for given access key. Click on Check all and Save. Copy your API key from the page and save it somewhere securely.

Set up a webhook server with Cloudflare Workers
In my previous tutorial A Beginner's Guide to Setting up Free Webhooks with Cloudflare Workers, I demonstrated how to set up a production-ready Webhook server that can be used for Patreon automation. We will catch up from there and build an App by adding business logic to that Webhook server. To get started, just create a new Worker and replace the code with the following one.
YOUR-SECRET_KEY_COPIED_FROM_PATREON
with the secret key.export default {
async fetch(request, env) {
try {
if (request.method === "POST") {
// get headers and request data
let requestHeaders = Object.fromEntries(request.headers);
const body = await request.json();
// computing hex
const encoder = new TextEncoder();
const myText = encoder.encode(JSON.stringify(body));
const secretKeyData = encoder.encode('YOUR_SECRET_KEY_COPIED_FROM_PATREON');
const key = await crypto.subtle.importKey(
'raw',
secretKeyData,
{ name: 'HMAC', hash: 'MD5' },
false,
['sign']
);
const mac = await crypto.subtle.sign('HMAC', key, myText);
const hex = Array.prototype.map.call(new Uint8Array(mac), x => (('00' + x.toString(16)).slice(-2))).join('');
// comparing signature
if (request.headers.get('x-patreon-signature') !== hex) {
// Webhook request did not come from Zoom
console.log('Request not authorized');
return new Response('Request not authorized', {
status: 401
})
} else {
// Webhook request came from Patreon
console.log('Authorized request');
return new Response('Authorized request', {
status: 200
})
}
}
return new Response("Access Denied")
} catch (e) { return new Response(err.stack, { status: 500 }) }
}
}
Code snippet for Webhook server
Add business logic to the Webhook server
The business logic is: when a new user pledges on your Patreon, the user will then gain access to a membership on aMember site.
Let's update the code for the Webhook server, and replace the code with below. Please replace the variables AMEMBER_DOMAIN
, ACCESS_KEY
, and PRODUCT_ID
with your own.
export default {
async fetch(request, env) {
const AMEMBER_DOMAIN = "YOUR_AMEMBER_DOMAIN"
const ACCESS_KEY = "YOUR_AMEMBER_ACCESS_KEY"
const PRODUCT_ID = "YOUR_AMEMBER_PRODUCT_ID"
async function gatherResponse(response) {
const { headers } = response;
const contentType = headers.get("content-type") || "";
if (contentType.includes("application/json")) {
return JSON.stringify(await response.json());
}
return response.text();
};
try {
if (request.method === "POST") {
// get headers and request data
let requestHeaders = Object.fromEntries(request.headers);
const body = await request.json();
// computing hex
const encoder = new TextEncoder();
const myText = encoder.encode(JSON.stringify(body));
const secretKeyData = encoder.encode('YOUR_SECRET_KEY_COPIED_FROM_PATREON');
const key = await crypto.subtle.importKey(
'raw',
secretKeyData,
{ name: 'HMAC', hash: 'MD5' },
false,
['sign']
);
const mac = await crypto.subtle.sign('HMAC', key, myText);
const hex = Array.prototype.map.call(new Uint8Array(mac), x => (('00' + x.toString(16)).slice(-2))).join('');
// comparing signature
if (request.headers.get('x-patreon-signature') !== hex) {
// Webhook request did not come from Zoom
console.log('Request not authorized');
return new Response('Request not authorized', {
status: 401
})
} else {
// Webhook request came from Patreon
console.log('Authorized request');
// Extract email address of the new user from Patreon's update
const email = body.included[0].attributes.email;
// get aMember user id with email address by calling aMember API
const checkURL = `http://${AMEMBER_DOMAIN}/api/check-access/by-email?_key=${ACCESS_KEY}&email=${email}`
const response = await fetch(checkURL);
const results = await gatherResponse(response);
const userID = JSON.parse(results).user_id;
// get today's date and set expiration data
const today = new Date().toISOString().slice(0, 10);
let expd = new Date();
expd.setDate(new Date().getDate()+365);
const exp = expd.toISOString().slice(0, 10);
// add access to product with user ID and product ID
const init = {
method: "PUT",
headers: {
"content-type": "application/json;charset=UTF-8",
},
};
const accessURL = `http://${AMEMBER_DOMAIN}/api/access/${userID}?_key=${ACCESS_KEY}&user_id=${userID}&product_id=${PRODUCT_ID}&begin_date=${today}&expire_date=${exp}`;
const newResponse = await fetch(accessURL, init);
const newResult = await gatherResponse(newResponse);
return new Response('Authorized request', {
status: 200
})
}
}
return new Response("Access Denied")
} catch (e) { return new Response(err.stack, { status: 500 }) }
}
}
Add the webhook server to Patreon and test it
Now let's add the Webhook server to Patreon and test it! Copy your Webhook server URL and paste it into your Patreon Webhook manager. In our example, the Webhook server URL is https://webhook.gludemo.workers.dev
.
Click the Send test button on the Create Pledge API call, and Patreon will push a test update to your Webhook server. The Webhook server will receive the update and add product access to the test user.
That's it! Now you have a free Webhook server with Cloudflare Workers that connect your Patreon account (as a creator) to your aMember site.
Wrapping up
In this tutorial, you have learned how to set up a production-ready webhook server with Cloudflare Workers. Connect your Patreon account (as a creator) to your aMember site. Should you have any questions, please feel free to login and comment here.