Took a bit of research, but I finally have Zapier Rest Hooks. Not as straightforward as I could hope for (most likely I'm a bit involved in the takeover). The customer support was great and friendly, so feel free to send them your questions. Also, once you get this work, it is VERY powerful, although their regular webhook mechanism also works and does not require the creation of a Zap application. At the time of this writing, I have not pushed the application, although it works locally. It is assumed that you started to create your own Zapier application in the developer toolbar. It’s pretty simple, so I won’t cover it here.
This explanation will only cover the creation of a single trigger (although you create another private one to support user authentication, and I created another for dynamic drop-down purposes) and only as a RESThook with Basic Auth. The basics:
1. Create web hosts to allow Zapier to add, update and delete subscriptions to their activities. "Subscribing" Zapier should not poll your webhook, rather, when the signed action happens on your side, you will respond to the URL that Zapier provided to you during the subscription process.
2. Create a DB table that registers these subscriptions, storing the data you need, then send the response back to the supplied Zapier URL when the action starts on your part.
3. When the action is triggered, find out that and publish the data that you told zapier that you are sending. Zapier is pretty smart and will display data (JSON or XML) for you, so when you connect to another application, the user can display between them.
So a few more details. This was done in C # on .Net, but I think that concepts should work just as well in any other language or platform.
RESTHooks first. The following is an example of RESTHook methods. Please note that I spent several days trying to figure out the script version of Zapier, so I'm not quite happy with the naming conventions, but I hope you get this idea.
In this scenario, there is the concept of a “form”, which is part of the JSON data that excites me, the user and the account to which the user belongs. All of them have a unique identifier in the system. Finally, the subscription itself has an identifier. When you sign up, a specific user in a particular account signs a specific form, which will be sent to Zapier when a specific trigger is executed (presentation of this form).
RESTHooks:
First, RouteConfig , which displays the path to the method being executed. You can see all the methods that I implemented. Some of them are not used and are simply included for possible future use (for example, to update a subscription).
// ZAPIER Webhooks routes.MapRoute( "User_Form_List", "api/zapier/user/formlist", new { controller = "Zapier", action = "RetrieveFormListForUser" }, new { httpMethod = new HttpMethodConstraint("GET") } ); routes.MapRoute( "Authenticate_Subscription", "api/zapier/authenticate", new { controller = "Zapier", action = "WebhookAuthenticate" }, new { httpMethod = new HttpMethodConstraint("GET") } ); routes.MapRoute( "Test_Subscription", "api/zapier/subscription/testdata", new { controller = "Zapier", action = "TestData" }, new { httpMethod = new HttpMethodConstraint("GET") } ); routes.MapRoute( "Create_Submission", "api/zapier/subscription/create", new { controller = "Zapier", action = "CreateSubscription" }, new { httpMethod = new HttpMethodConstraint("GET") } ); routes.MapRoute( "List_Subscriptions", "api/zapier/subscription", new { controller = "Zapier", action = "ListSubscriptions" }, new { httpMethod = new HttpMethodConstraint("GET") } ); routes.MapRoute( "Get_Subscriptions", "api/zapier/subscription/{id}", new { controller = "Zapier", action = "GetSubscription", id = 0 }, new { httpMethod = new HttpMethodConstraint("GET") } ); routes.MapRoute( "Update_Subscription", "api/zapier/subscription/{id}", new { controller = "Zapier", action = "UpdateSubscription", id = 0 }, new { httpMethod = new HttpMethodConstraint("PUT") } ); routes.MapRoute( "Delete_Subscription", "api/zapier/subscription/{id}", new { controller = "Zapier", action = "DeleteSubscription", id = 0 }, new { httpMethod = new HttpMethodConstraint("DELETE") } );
Corresponding to this code (also I pulled out error handling to reduce code size):
public class ZapierController : BaseController
The DB table in which the subscriptions will be stored is as follows. I will leave the side of reading and writing, as you may have a different mechanism.
Create.Table("WebhookSubscription") .WithColumn("Id").AsInt32().Identity().PrimaryKey().NotNullable() .WithColumn("AccountId").AsInt32().NotNullable() .WithColumn("UserId").AsInt32().NotNullable() .WithColumn("EventType").AsString(256).NotNullable() .WithColumn("TargetURL").AsString(1000).NotNullable() .WithColumn("IsActive").AsBoolean().NotNullable() .WithColumn("CreatedOn").AsDateTime().Nullable() .WithColumn("FormId").AsInt32().NotNullable().WithDefaultValue(0); .WithColumn("UpdatedAt").AsDateTime().Nullable();
To be clear, value / usage for the following columns:
- Id is a unique subscription identifier. Will be used to unsubscribe
- AccountId - account identifier for user subscription. If you want all of them to work at the account level, you could simply do this instead
- UserId - user subscription identifier
- EventType The type of event your action responds to, for example, "new_form_submission"
- TargetURL . The destination URL that zapier gave you when signing up. Will there be a placement of your JSON when the action is triggered.
- FormId - identifier of the form in which the user wants to perform an action when submit
So, this is the code needed to subscribe (obviously, you can't just throw it in there and make it work - left a good amount to save space) ...
Trigger code
Only the code on the left is the actual trigger code — the code that you execute when the event search is found in your code. For example, when a user submits a "form", we want to submit this JSON form to Zapier. Now that we have all the other code, this part is pretty simple. First, the code, in order to discover that we got the view, requires a Zapier response:
Actual code that looks if registered / registered on Zapier:
public BusinessResult FormSubmitted(string jsonString) { var json = CommonUtils.DecodeJson(jsonString); var account = _DBrepository.AccountRetrieveById(_currentUser.AccountId.Value); // Assumes user has bee authenticated // inject additional meta data into json and retrieve submission/alert settings var form = _DBformRepository.FormRetrieveById((int)json.formId); // Lookup Subscription Webhooks List<WebhookSubscription> subscriptions = _DBrepository.accountWebhookSubscriptions(account.Id); if (subscriptions != null && subscriptions.Count > 0) { foreach (WebhookSubscription sub in subscriptions) { if (sub.EventType.Equals("new_form_submission") && sub.FormId == form.Id) { _webhookService.NewFormSubmission(sub, jsonString, form.Name, account.Name, account.Id); } } } }
And finally, the code to send the response back to Zapier, which will parse the JSON and send it to the appropriate parties:
public class WebhookService : IWebhookService { protected readonly IRepository _DBrepository; public WebhookService(IRepository repository) { _DBrepository = repository; } public void NewFormSubmission(string formResultJSON) { throw new NotImplementedException(); } public void NewFormSubmission(WebhookSubscription subscription, string formResultJSON, string formName, string accountName, int accountId) {
Well, that should get you most of the way. But posting code / webhooks in Zapier is where it gets a little trickier. The idea now is to link code in your Zapier application using the development panel. You will need to start creating the Zapier app. You need two main triggers: the main action that you are trying to implement (in this case, “Submit a new form”) and authentication, so that Zapier can authenticate the user as he creates Zap (in this case, “Test Auth”), I use Basic Auth, but others are supported (OAuth, etc.). In addition, I added a trigger that will return a list of forms that the user has access to. Since this is not required, I will not show that the implementation is fixed on the screen:
I will not show the wiring for Test Auth, as it went quite smoothly (I will add it if someone asks for it - heaven knows, someone will even read it). So, here is the posting, page by page for "Submit a New Form":
Page 1

Page 2
Here I am attaching a list of forms that provides a list of forms that the user who creates Zap can select. You can probably skip this (leave it blank) if you don't have the dynamic data you want to display. I have included it for completeness: 
Page 3
Here you connect test data

Page 4
On this page you can enter sample data. Skipping this, as it is pretty straight forward.
Scripting API
So, now you have connected your first Zap Trigger! But wait, we are not done. To make the subscription process, we need to add some script. It was the hardest part of the whole process and was not very intuitive. So, on the initial main screen, a little lower, you will see the scripting API :

You should now have a script to subscribe to RESTHook. I am not going to understand in detail, since Zapier has documentation about this, but it’s good to know that Zapier stores data as part of the subscription. Also after that we will need to take another connection step ...
var Zap = { pre_subscribe: function(bundle) { bundle.request.method = 'GET'; bundle.request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; bundle.request.params = { target_url: bundle.subscription_url, target_event:bundle.event, form_id:bundle.trigger_fields.form_id }; bundle.request.data = $.param({ target_url: bundle.subscription_url, target_event:bundle.event, form_id:bundle.trigger_fields.form_id }); return bundle.request; }, post_subscribe: function(bundle) { // must return a json serializable object for use in pre_unsubscribe var data = JSON.parse(bundle.response.content); // we need this in order to build the {{webhook_id}} // in the rest hook unsubscribe url return {webhook_id: data.id}; }, pre_unsubscribe: function(bundle) { bundle.request.method = 'DELETE'; bundle.request.data = null; return bundle.request; }, new_form_submission_pre_poll: function(bundle) { bundle.request.method = 'GET'; bundle.request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; bundle.request.params = bundle.trigger_fields; bundle.request.data = $.param({ form_id:bundle.trigger_fields.form_id }); return bundle.request; } };
There is little for this ... but look at the Zapier documentation and this should help. Or ask questions here and I will try to answer them ... this is getting bigger than I expected!
Manage trigger settings
Finally, we need to finish the wiring for the subscription ...

Then we create the RESTHook methods that we created some time ago:

And it's all. Hope this saves you time and lessons!