Solve Webhooks Examples

Solve CRM Webhooks


Webhooks are settings that tell Solve to listen for changes made to data in your Solve account. When these events occur, Solve calls a script on your web server, which can act in any way you want.

Hooking is a technique used to alter or augment the behavior of a program without having access to its source code. It solves a broad range of customization needs, such as:

  • I wish that my web-apps would keep data in sync
  • I wish that I could make another app do something when I use this app
  • I wish that I could make this app work slightly differently

Imagine the following real-world examples …

  • When a specific category tag is added to a contact, a template of activities is conditionally inserted.
  • When a contact is created or updated in Solve the data is instantly updated in your other business application(s).
  • When a task is completed, the next step is automatically set-up according to your pre-defined rules e.g. create a new task, recalculate a value, or update a report.

An infinite number of useful real solutions, like these ones, can be quickly implemented using “Webhooks”.

One-minute webhook demo

Step 1 - Register a URL to send the webhook notification to

To demonstrate how easy it is to get started with webhooks we’ll use a free “Postbin” web service that will receive and log the notification from Solve. There are many such services; use Google to find other ones. A Postbin provides a unique URL where you can monitor all POST HTTP requests it receives.

For this example open (or any other Post’bin service you found) > click “Create a Request Bin” > copy the endpoint address created for you > don’t close the window.

Step 2 - Create a webhook in Solve

  1. Solve menu > Add-ons > Enable Webhooks
  2. Solve menu > Configure Webhooks > Add
  3. Enter the URL you copied from step 1 e.g.{someValue} > OK
  4. Check “Active” to enable the hook > leave the other parameters defaulted
  5. Update a contact in Solve e.g. change a field or add a category tag
  6. Refresh the Postbin browser window e.g.{someValue} > you’ll see the information received about the update you just made

As easily as this you can enable webhook notifications on a wide range of interesting events happening in Solve, and have your own custom application / script act on them.

Comparing Solve Webhooks with the Solve API

“How are webhooks different than the API?”

  • You call the API from a custom script you write. The API responds to your script’s request to read or update information in the Solve account. You decide when your script runs and what it should do with the data in the account.
  • Webhooks notify you as changes happen in the Solve account. Your script can respond to that specific event in real-time.

Webhooks and the API are partners. Webhooks triggers the action (gets things going) and the API provides access to read and update information (analyse more data and make other updates).

Working code examples described

Making webhooks work in your business

We’ve prepared a free set of example scripts that demonstrate how webhooks can be put to work in real-world situations. The examples cover frequently asked about use-cases, so there’s a good chance you don’t have to do much to them to make them support your own requirements.

When a Solve webhook calls out, you need your own script, running on your own server, in place to receive that information. You can often place this script on your existing website, or if you’re a Google Apps user perhaps now is a great time to take a look at Google’s “Google App Engine” service.

A real world case put into action

Your team has realized great value by storing and managing client information efficiently in Solve. They’ve refined their workflow to the point where it would be nice to have the system take over some of the repetitive steps for them now. Let’s summarize their new requirements:

  1. We have a new lead The system automatically assigns it to an Salesperson based on predetermined rules and instantly sends the newly assigned Salesperson a “get busy” email notification so no time is wasted.
  2. We’re rolling with a new client! Add the “Client” category tag to their record and have the system automatically add a set of pre-planned and pre-assigned activities and record how long it took to convert them from a lead.
  3. Whew, contract signed … When the “receive contract” task is completed have the system instantly synchronize the client’s details to your customized office application and sends an email notification to Mr. Boss announcing the good news.

What you’ll need

With any webhook solution you’ll need to 1) have a URL with a script ready to process the incoming notification, and 2) configure the webhook(s) in Solve.

For the URL you’re going to need access to a web server (perhaps the one hosting your website), or a third party application hosting service, or Google App Engine. All the example scripts are available in both PHP (supported by most web servers) and Python (for Google App Engine) scripting languages. Configuring the webhooks is something that we’ll walk you through with a few simple steps.

Examining each business process

1. We have a new lead

Regardless of how the lead got into the system, the webhook will notice it and automatically assign it to a Salesperson based on predefined rules: We’ll check if the contact has values for “last name” and “email address”, that it has been tagged as a “Lead” and that it has not been “assigned to” someone yet. Then if the conditions are met, we’ll assign that contact to one of three designated Salespeople based on the first letter of the contact’s last name (A-G, H-P, Q-Z). We’ll also send the newly appointed Salesperson an email notifying them of the new lead.

2. We’re rolling with a new client

As soon as a contact has the “Client” category tag applied to it, we’re going to determine if the “New Client” activity template has been applied to it yet; if not, we will apply it. Since the “Client” tag was added we’ll ensure the “Lead” tag is removed. We’ll also calculate how long it took to close the deal by subtracting today’s date from the contact’s created date.

3. Whew, contract signed

We need to catch the moment when a task with title “Receive contract” is completed which will cause the system to sync the contact record to a local database and send an email notification to the boss.

The local database can be whatever you’re comfortable with. For demonstration purposes we are going to use a simple db.xml file for the PHP version of the script and Google App Engine Datastore for the Python version.

Implementing the working code examples

To follow the business case examples, carefully make these changes in your Solve account:

  1. Create two contact category tags named: “Lead” and “Client”.
  2. Create a custom number field for contacts named: “Days to close”
  3. Create a template of activities you wish to add to a new lead, one of those activities should be a task titled “Receive contract”
  4. Create a contact with a First name, Last name and email address (the script checks that these fields have values to start the workflow)

Getting the URL working with the example scripts

While some web-master skills are required to install this example and customize it to your particular needs, you can still use it as is with almost no change. Just comment the parts you don’t need as highlighted in the primary script file and only set up webhooks desired.

If using PHP 5 server

Download to your local computer. Copy the three files in the Zip file to your PHP server:

Primary script
Database file
Function library

Set db.xml to writable by the PHP process e.g. run “sudo chmod 777 db.xml” to be writable

Edit endpoint.php and change the “Configuration constants” to reflect your own Solve settings e.g. yourSolveEmailAddress, yourSolveToken… The IDs of users, fields, templates and category tags are listed in your Solve account under Solve menu (top-right) > My Account > API Reference.

The URL you will use in the webhook configuration will be http://{yourServerUrl}/{yourDirectory}/endpoint.php


Now skip ahead to “Creating the webhooks”

If using Google App engine (Python)

Download to your local computer. Copy the three files in the Zip file to a new directory on your local computer:

Primary script
Application config
Function library

Edit and change the “Configuration constants” to reflect your own Solve settings e.g. yourSolveEmailAddress, yourSolveToken … The IDs of users, fields, templates and category tags are listed in your Solve account under Solve menu (top-right) > My Account > API Reference.

You should review Google’s documentation on getting started with Google App Engine and Python. For the purposes of this example we’ve summarized the steps for you here:

Install Google App Engine SDK

Download and install Python 2.7 and the Google App Engine SDK for your OS type.

Register a new application in Google App Engine Dashboard

  1. Open > “Create Application”.
  2. Enter a unique “Application Identifier” and “Application Title” e.g. “Solve CRM Workflow Extension”
  3. Notice the URL of your application, it will be needed to create the webhooks in Solve
  4. Confirm by clicking “Create Application”

Upload the example application

  1. Open app.yaml and change “yourGoogleAppID” to the unique “Application Identifier“ you registered in the Google App Engine Dashboard
  2. Open Google App Engine Launcher on your local computer > File > Add existing application > set “Application path” to be the directory where you saved the three example files > Add
  3. Select your application in the list > click “Deploy” > enter your Google account credentials > OK.

The app is now ready to process webhooks requests. The URL you will use in the webhook configuration will be http://{Application Identifier}

Creating the webhooks

  1. Solve menu > Add-ons > confirm the Webhooks add-on is enabled.
  2. Solve menu > Configure Webhooks > create the three webhooks as shown in the screenshot below. Recall for PHP the URL is http://{yourServerUrl}/{yourDirectory}/endpoint.php and for Google App Engine it’s http://{Application Identifier}

Set the “Secret” field to the value you used for the yourSecret parameter in the endpoint file.

Now lets test our solution …

Testing the solution

  1. Enable all three wehbooks clicking on their respective “Active” checkbox.
  2. Add the “Lead” category tag to the contact you created in a previous step > wait a few seconds > click “Refresh view” > you should see that the designated Salesperson was assigned to the contact and received an email notifying them of the assignment.
  3. Add the “Client” category tag to the same contact > wait a few seconds > click “Refresh view” > you should see that the “Lead” tag has been removed, your specified template of activities was inserted on the contact and a value in the “Days to close” field calculated and saved.
  4. Complete the “Receive contract” task on the same contact > the email address you entered for yourBossEmailAddress should have received an email notification. If you’re using PHP the db.xml file should have been updated with the new client’s contact information. If you’re using the example for Google App Engine, the data will be synced to the built-in Datastore. To observe the datastore > Dashboard > Data > Datastore Viewer. If the contact is already in the local database an email will not be sent.
  5. Return to the Webhooks settings > click the “Refresh” button and you’ll see some information in the Log field which is helpful in monitoring the result of your webhooks.

What to check if you don’t get the result you expect

  • If you use the PHP version, check your PHP errors file and, if needed, the web server log. Make sure error_reporting is enabled.
  • If you use the Google App Engine version, find “Logs” in the application Dashboard. All errors are logged there.
  • If there is no error in the logs and the hook doesn’t fail, just not doing what it supposed to do: try to debug the script to see the code flow. Read official PHP/GAE documentation to find out about the debugging routines.

Next steps

  • Review the code in the endpoint.php/py file. It’s designed to be easy to follow. Imagine how you could make simple modifications to the logic in this file to support custom workflow sequences.
  • Review the “Technical overview” section below to learn the details behind all the various webhook options and what else it’s capable of doing for you.

Technical overview

Configuring webhooks

A checkbox for turning the hook on and off. Make sure to enable the hook once it’s configured and the endpoint application is in place.
Sometimes it’s possible for a hook to be turned off by the system. Read more in “Repeating Strategy”
A common name for a hook, exclusively for your convenience. Not required.
To create a webhook you have to enter the endpoint url. This must be a publicly available resource/script/application that will handle the callbacks Solve will make with relevant event information. Your custom application must return 200 or 201 status code or the request will be considered failed (See “repeating strategy”).
Here you can choose what type of items/activities you’re interested in, in case you don’t want to filter them on your end. For instance, you can choose only updates happening to tasks to be sent to you.
The type of the event. Here is the list of the events available at the moment:
  • items.update
  • items.create
  • items.delete
  • items.restore
  • items.categorize
  • items.uncategorize
  • activities.create
  • activities.update
  • activities.delete
  • activities.restore
The system will listen to this event and when it happens, it will send a notification to your webhook endpoint as well as all relevant object information.
Content type
Here you choose the format for the data we’ll send to you. There are three available at the moment:
  • XML
  • JSON
  • Form encoded
Following best practices of our current version of the Solve External API, the XML format has more metadata available in attributes such as actual fields labels and full user names. It also marks items fields that have changed with the changed="true" attribute.
“Form encoded” means that the data will be formatted just like if you had submitted an HTML form. It may be easier to access POST variables than reading and parsing XML data, in some scenarios.
This is an optional security measure. The value you set will be used as KEY to create a sha256 hash for the full request body. It will be then sent as the “X-Solve360-Hmac-Sha256” header.
In your endpoint you can check the hash to be valid to confirm the request is coming from Solve CRM.
Here is how you’d do it in PHP:
# Fetching headers via apache_request_headers()
$headers = apache_request_headers();
if (hash_hmac('sha256', $postdata, $secret) !== $headers['X-Solve360-Hmac-Sha256']) {
  header('Unauthorized', true, 401);
# Fetching headers via $_SERVER
if (hash_hmac('sha256', $postdata, $secret) !== $_SERVER['HTTP_X_SOLVE360_HMAC_SHA256']) {
  header('Unauthorized', true, 401);

… and here is one for Python:

secret_check =, postdata, hashlib.sha256).hexdigest()
if secret_check != self.request.headers.get('X-Solve360-Hmac-Sha256'):
This column you cannot edit. It presents the list of most recent requests done for this webhook. You can see when they happened and whether they were successful or not.


Regardless of the particular content type chosen, a notification your endpoint will receive is structured as follows:

e.g. items.update
The ID of the object that was updated/created/deleted, etc.
This one will contain the actual data of the object (just so you don’t always have to use the API to get the data). Entity data is formatted in the same way as for external api.

XML notification example

<?xml version="1.0" encoding="utf-8"?>
    <name>Test Project Blog</name>
      <title label="Title">Test Project Blog</title>
      <custom69032 label="Custom date">2012-10-12</custom69032>
      <custom69033 label="Custom textarea" changed="true"/>
      <creatorname>Steve Ireland!</creatorname>
      <modificatorname>John Smith</modificatorname>
      <creatorname>John Smith</creatorname>
        <details>Very important note</details>
      <modificatorname>John Smith</modificatorname>
      <name>Very important note</name>

JSON notification example

       "name":"Test Project Blog",
          "title":"Test Project Blog",
          "creatorname":"John Smith",
          "modificatorname":"John Smith",
          "creatorname":"John Smith",
             "details":"Very important note",
          "modificatorname":"John Smith",
          "name":"Very important note",


Form encoded notification example


Although the form encoded example is not nice to observe by hand, you can access data conveniently in the app, e.g. in PHP, as an array:

echo $_POST['type']; // - will echo “items.update” 

Endpoint implementation

The endpoint can be a script or an application of any scale, implemented in any language on any platform. It just needs to be publicly accessible online and return the response with status code less than 400. Generally, 200 is expected.

Retrying failed webhook calls

If your endpoint returns a status code of an error (> 400) we’ll consider this request as failed. You will be able to see it as “Failed” in the logs. We’ll then try to repeat each failed request about every 30 minutes until it succeeds; but not more than 4 times. Each retry will produce an entry in the webhook log.

If all retry attempts fail a webhook failure email notification is sent to the organization administrator. The email includes the original webhook notification details which can be used to remedy any data consistency issues caused by the failure(s).