To Top

Consuming A Webhook With FileMaker

What Is A Webhook?

A webhook (sometimes known as an HTTP callback or Reverse API) is an HTTP request (usually a POST or GET) made by a web application in response to an event taking place that is worthy of notification or some other action taking place. They will often include details of the event, which we can use to, say, update records. Usually, within the dashboard configuration of the service or web application, there will be a place where you can enter the URL of where you want these HTTP requests to be sent - this is sometimes referred to as the endpoint. Some examples for context are below.

Twilio
Twilio uses webhooks in a multitude of ways, but one example is the delivery status of a SMS message. When sending a message with Twilio, the initial status of the message is 'Sent' but shortly after the message status will change to 'Delivered' at which point Twilio will invoke the webhook. If we receive that webhook and process it, we can update the status of that message record in our database to be 'Delivered'.

Stripe
An example of Stripe using webhooks could be as simple as receiving a payment from a customer. The webhook calls our endpoint with the details of the payment just made, and we could take that information and mark an invoice as paid. No user interaction is necessary.

Slack
If you create a Slack app, you can have buttons on your app messages that a user can click and it will use a webhook to send those details to your endpoint. We use this in our OverWatchFM FileMaker Server Monitoring Service.

Consuming A Webhook

There will be a bunch of code in this blog post but we are also providing demo files that are easy to set up and start using. It's worth noting that this technique is intended for POST requests, where the web app is sending you a chunk of data based on an event having taken place. We'll be utilizing some PHP files (which will need to be hosted on a web server) and the FileMaker Data API to consume the webhook. To that end, you'll need to take care of the following items:

  • Set up your FileMaker layout for the Data API to use
  • Create a field that will be used to store the data passed in from the webhook
  • Set up your FileMaker script that the Data API will call
  • Set up your FileMaker Data API user account with the correct privileges
  • Ensure FileMaker Server is configured to use the Data API
  • Update the PHP files with your details and upload to a web server
  • Configure your web application/service with the endpoint URL (where you uploaded the files to)

In outline, this is what we'll be doing:

  • The webhook will call our endpoint and we'll request an authorization token for our database using the Data API
  • Using that token, we'll grab the data we were passed by the web app and then have the Data API create a record and run a script - what table you create the record in and what the script does is entirely up to you, it just depends what you want to do with the data passed
  • Then for good measure we'll delete the authorization token

Let's take a look at each of the PHP functions we'll be using, and then the code that runs those functions. The functions are essentially cURL calls and while they could be optimized, we've kept them separate for each section for ease of reading and learning.

Getting A Token

This function gets our token:

// Function to get an authorization token from FileMaker which will be used to pass data from the webhook to the database - note, environment variables are set just before function is called
function get_token($additionalHeaders,$host,$password,$payload,$username) {

	// Set up the cURL options
	$ch = curl_init($host);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', $additionalHeaders));
	curl_setopt($ch, CURLOPT_HEADER, 0);
	curl_setopt($ch, CURLOPT_USERPWD, $username . ":" . $password);
	curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	
	// Execute the cURL statement
	$result = curl_exec($ch);

	// Close the cURL connection
	curl_close($ch);

	// Decode the resulting JSON
	$json_token = json_decode($result, true);

	// Extract just the token value from the JSON result
	$token_received = $json_token['response']['token'];
	
	// Return the token
	return($token_received);

};

Passing The Data To FileMaker

This function passes the data to FileMaker:

// Function to pass data from the webhook to the database using the token from the function above - note, environment variables are set just before function is called
function pass_data($additionalHeaders,$host,$payload) {
	
	// Set up the cURL options
	$ch = curl_init($host);
	// Inject the token into the header
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', $additionalHeaders )); 
	curl_setopt($ch, CURLOPT_HEADER, 0);
	curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	curl_setopt($ch, CURLOPT_POST, 1); 
	curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

	// Execute the cURL statement
	$result = curl_exec($ch);
	
	// Close the cURL connection
	curl_close($ch); 

	// Return the result
	return($result);

};

Deleting The Token

And finally, this function deletes the authorization token:

// Function to delete the authorization token
function delete_token($additionalHeaders,$host,$payload) {

	// Set up the cURL options
	$ch = curl_init($host);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', $additionalHeaders));
	curl_setopt($ch, CURLOPT_HEADER, 0);
	curl_setopt($ch, CURLOPT_TIMEOUT, 30);
	// Specify the request method as DELETE
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); 
	curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	
	// Execute the cURL statement
	$result = curl_exec($ch); 
	
	// Close the cURL connection
	curl_close($ch); 

	// Return the result
	return($result);

};

Setting Up The Environment Variables

This section of the code, as we begin to execute our functions, is the only section that you will need to adjust. Add your details between the single quotes for each variable:

// Set up the environment variables for the hostname, database, layout, script and field name
$database = 'DATABASE_NAME';
$hostname = 'MY.SERVER.COM';
$layout = 'DATA_API_LAYOUT';
$script = 'SCRIPT_TO_EXECUTE';
$field_name = 'FIELD_NAME'; // Set up the FileMaker username and password that has data API privileges $username = 'USERNAME'; $password = 'PASSWORD';

Get The Authorization Token

In our first function call, we request the token from the database and store the result in the variable $token:

// Set up the environment variables to get a token
$additionalHeaders = '';
$host = 'https://'.$hostname.'/fmi/data/v1/databases/'.$database.'/sessions';
$payload = '';

// Call the get_token function and put the result into a variable for use in the pass_data function
$token = get_token($additionalHeaders,$host,$password,$payload,$username);

Send The Data To FileMaker

Our second function call uses the token we just received and sends the data from the webhook to FileMaker. We will create a new record, set the data from the webhook into the field defined above, and pass that data in the script parameter as well (although that is perhaps not necessary):

// Get the data from the webhook
$data = (!empty(file_get_contents('php://input')) ? file_get_contents('php://input') : json_encode($_REQUEST)) ;

// Now that we have a token, set up the environment variables and call the pass_data function to create a record and then run a script
$additionalHeaders = 'Authorization: Bearer '.$token;
$host = 'https://'.$hostname.'/fmi/data/v1/databases/'.$database.'/layouts/'.$layout.'/records';
$payload = json_encode(array('fieldData' => array( $field_name => $data ), 'script' => $script, 'script.param' => $data ));

// Call the pass_data function
$request = pass_data($additionalHeaders,$host,$payload);

Delete The Authorization Token

Our final function call deletes the token so it can't be used again:

// Set up the environment variables to delete the token
$additionalHeaders = '';
$host = 'https://'.$hostname.'/fmi/data/v1/databases/'.$database.'/sessions/'.$token;
$payload = '';

// Call the delete function
$token_deleted = delete_token($additionalHeaders,$host,$payload);

Response Time Limit

We discovered during one of our implementations that the web app calling the endpoint expected a response from our PHP page within about 2-3 seconds of it having hit the endpoint. If it did not receive the response in this timeframe, it would alert the user that triggered the event of an issue. While the Data API was doing its thing, it was taking longer than 3 seconds to get the token, create the record, run the FileMaker script, delete the token and return a response to the web app. So, to get around this we created a second PHP file that became the endpoint for the web app, and this file calls our first PHP file without waiting for the result. This code looks like this (be sure to update the last line with the location of the Data API PHP file):

function call_consume_webhook($url,$post_array) {
    
    // Get the data passed into this by the webhook
    $data = (!empty(file_get_contents('php://input')) ? file_get_contents('php://input') : json_encode($_REQUEST)) ;

    // Set up the curl request using the data from the webhook and the url when the function is called below
    $cmd = "curl -X POST -H 'Content-type: application/json' -d '[$data]' $url";

    // Instruct the command to run without waiting for it to complete, which may be required for services that have a response time limit
    $cmd .= " > /dev/null 2>&1 &"; // Just dismiss the response

    // Execute the command
    exec($cmd);

}

// Call the function, passing in the url
call_consume_webhook('https://my.server.com/consume-webhook-data-api.php',[]);

Downloads

So, if you're still with us, that's an awful lot of code, much of which you don't need to worry about. You can download a zip file of both PHP files here.

Caveats

There are some things to be wary of with consuming webhooks like this:

  • Any loading of the PHP file will trigger the Data API to execute its tasks
  • Given the above, be sure to bury the location of the file on the web server of choice
  • Within your logic in FileMaker it's probably a good idea to test if the data you're receiving is what you expect and if not then halt
  • It's also possible to add a unique token to the URL, such as "?auth=5487951", and drop the request if the token doesn't match what it should
  • There's little to no error trapping in these sample files, so if say the password changes for the user account, you will likely lose the data sent in the call
  • Some webhooks can make an awful lot of calls in quick succession, so be sure to know the volume you expect before setting this up

Conclusion

Claris has made interacting with web services easier and easier with each release over the last few years, with Insert From URL, then adding cURL options and native JSON functions to deal chunks of data. Being able to consume webhooks and get information from the web services without polling them at intervals further extends how we can take advantage of the many services out there and build smarter and better apps for our clients. If you need some help with webhooks or integrating with web apps then don't hesitate to get in touch.

And if you need general help with your FileMaker app, or want to save money on your licensing of Claris products, contact us and we'll be glad to assist.