Webhooks, Service Hooks, and Captain Hooks

disney_captain_hook.jpg

  1. Overview
    1. What Are Webhooks?
  2. Hookable Cheddar Events
    1. New Subscription
    2. Subscription Changed
    3. Subscription Canceled
    4. Subscription Reactivated
    5. Customer Deleted
    6. Transaction
    7. Subscription Billable
    8. Bill Reminder
  3. Configure Webhooks
  4. Integrations with Zapier
    1. Getting Started with Zapier
  5. Custom URLs
    1. Data Format and Definition
      1. Data Common To All Hooks
      2. Hook-Specific Supplemental Data
        1. Subscription Changed
    2. Security
      1. SSL
      2. Request Signature Verification
        1. Ruby Example
        2. PHP Raw Example
        3. PHP Zend Framework Controller Example
        4. C# Example
      3. X-CG-Token Header
      4. Restrict By IP
    3. Testing
      1. See A Post
      2. Rerunning Hooks
      3. Testing Hooks In Your Development Environment
  6. Fault Tolerance, Retries, and Reporting
    1. Affirmative Response
      1. Timeouts
    2. Automatic Retries
      1. Idempotence
    3. Manual Retries and Canceling Retries

1. Overview

Webhooks make it possible to automatically share the valuable data about customers, transactions, and billing activity contained in your Cheddar product account with external services. This feature gives you the ability to distribute your Cheddar data to other apps in your tech stack or easily customize Cheddar's default billing logic.

You should consider using webhooks if you'd like to do things like:

  • Add customers to a CRM system when they subscribe
  • Update your accounting system when a transaction runs in Cheddar
  • Compile billing data to create custom reporting
  • Use an external payment processor
  • Add custom charges or credits to customer's invoice when it becomes due

Webhook functionality is included with all Cheddar service levels. No additional fees apply. Some hooks may require a third-party account.

1.1 What are Webhooks?

Webhooks, or service hooks, are basically event notifications sent by Cheddar to external services with helpful data attached. If you have this feature enabled in your Cheddar product account, we'll automatically send webhooks to any hook listeners (the external service that receives the data) you have configured when certain events happen in your product account.

There are two types of listeners available: Zapier and Custom URLs. Zapier is a tool you can use to build custom integrations without having to write code. Use a Custom URL to customize Cheddar's billing behavior or to utilize your own listener logic. See the Zapier and Custom URL sections below for more information.

3. Hookable Cheddar Events

Below is a list of events which are "actionable" via the webhooks system. These events occur naturally within Cheddar during the course of its regular duties. When you enable a listener, you can choose which of these events Cheddar should automatically send to your listener.

3.1 New Subscription

A New Subscription event occurs when a new customer is created in Cheddar. This could occur via any one of several possible actions: API call, your Cheddar dashboard , Hosted Payment Create Page, etc.

3.2 Subscription Changed

This event occurs when a customer's subscribed pricing plan is changed.

3.3 Subscription Canceled

The Subscription Canceled event occurs upon any cancellation. Cancellations can occur automatically - as a result of non-payment for example - but also can be explicitly initiated via the API or GUI.

3.4 Subscription Reactivated

A Subscription Reactivated event occurs when a previously canceled subscription is successfully reactivated.

3.5 Customer Deleted

If a customer is deleted via the API or Cheddar dashboard, a Customer Deleted event occurs.

3.6 Transaction

The Transaction event is triggered by any transaction. A transaction could be for a recurring subscription invoice, one-time invoice, refund, or void. This event is triggered when any transaction is executed with any result. It is also triggered when a transaction is updated with settlement information (e.g., PayPal Echeck or normal ACH).

Differentiating the types of transactions is accomplished by examining the hook payload:

  • Refund: The subscription[invoice][transaction][parentId] will contain a value (the id of the refunded transaction) and the subscription[invoice][transaction][amount] will contain a negative value.
  • Void: The subscription[invoice][transaction][response] will have a value of "voided".
  • One-time Invoice: The subscription[invoice][type] will have a value of "one-time".
  • Recurring Invoice: The subscription[invoice][type] will have a value of "subscription".

For more information about the data your listener will receive from a Cheddar hook, see the data common to all hooks section below.

3.7 Subscription Billable

The Subscription Billable event is triggered by the recurring engine when an invoice becomes billable. If a hook is registered for the Subscription Billable event, the recurring engine will not execute the invoice immediately. Rather, the hook is sent which gives you (or more accurately your hook listener) the opportunity to execute arbitrary actions prior to transacting the invoice. Only after all Billable hooks are successfully processed by your listeners will the invoice be transacted. For more information, see the Invoice Review article.

3.8 Bill Reminder

The Bill Reminder event is triggered according to your settings.

3. Configure Webhooks in Cheddar

Configure webhooks in your Cheddar product dashboard by visiting the "Configuration" menu and selecting Service Hooks. From there, select your hook listener: Custom URL or Zapier.

If you're using a Custom URL, enter the URL that will receive hook data (listener) and choose the events that will trigger a hook being sent to that listener. You can configure as many hook listeners as you'd like. Once your listeners are configured, hit save and Cheddar will begin sending hooks right away.

Custom URL listeners can be turned on and off. When turned back on, they pick up right where they left off with your credentials intact. To toggle a service on or off, just check or uncheck their "Active" box

If you're using Zapier, you'll manage hooks from your Zapier dashboard rather than your Cheddar dashboard.

Once hooks are activated, Cheddar will log all the events sent on your behalf in the Hooked Activity Log. You can view this log by visiting the "Activity" menu in your Cheddar dashboard and selecting "Hooked Activity".

Cheddar has fault tolerance built into the hooks system that will automatically try to resend a hook if it fails to reach your configured listener, but you also have the option to manually retry the hook from the hooked activity log. Select the check box next to the hooks you’d like to resend and retry.

4. Integrations with Zapier

Zapier is a service that routes webhooks between platforms. Without writing any code, you can configure Zaps that will automatically take hooks fired by Cheddar and direct them to a 3rd party application to perform an action based on the data that was received.

In practical terms, this tool allows you to build custom integrations with any of the thousands of apps supported by Zapier with ease. Our customers often use this tool to automate actions like:

  • Transferring transaction data from Cheddar to accounting systems like Quickbooks
  • Updating custom reports in Google Sheets
  • Creating a Slack notification when a new customer signs-up for a subscription
  • Updating your CRM, like Salesforce or Agile, when customers sign-up or change their subscriptions

See more examples here.

4.1 Getting Started with Zapier

Sign-up for a Zapier account here.

Then create your first Zap! You'll create and manage Zaps within your Zapier account. Zaps are like recipes for automating tasks between two web applications. They are made up of 2 primary components:

  • Triggers
  • Actions

You can use Cheddar's hookable events as triggers, then select any of Zapier's supported apps where the action will take place. Once the Zap is live, Zapier will begin automatically performing the actions you've configured whenever a trigger is received.

To connect your Cheddar product account to Zapier you'll need your Cheddar username, which is the email address you use to log in, and your product account's secret key. You can find your product secret key here.

When you're configuring an action, you may also have the option to apply specific fields from the trigger data to go to the action.

For example, let's say you'd like approved transactions from Cheddar to trigger an action to update to the customer record in your CRM platform. The transaction trigger is fired by Cheddar when a transaction with any result takes places (approved, declined, error, refund, void).

To ensure the customer update action only happens when a transaction is approved you can filter the action based on the subscription[invoice][transaction][response] field having a value of approved. To see other data contained in Cheddar triggers see the Data Common to All Hooks section.

Those are the basics, but if you're looking for in-depth documentation, see Zapier's 'How to Create A Zap Guide' here.

5. Custom URLs

If you'd rather route your webhooks yourself or create your own listener logic, you can create a custom hook listener. Cheddar provides the capability to send hook data to any URL you choose. Configure a custom hook URL within your Cheddar dashboard. When the Custom URL hook is enabled, Cheddar automatically sends HTTP POST data to the URL whenever the trigger events you've configured occur. You may configure an unlimited number of listeners for webhooks.

5.1 Data Format and Definition

Data is sent in either application/x-www-form-urlencoded or application/json format (your choice!) to your listener via HTTP POST.

5.1.1 Data Common to All Hooks

Name Description
activityType The event type: newSubscription, subscriptionChanged, subscriptionCanceled, subscriptionReactivated, subscriptionBillable, customerDeleted, transaction
activityDatetime The moment the event occured in ISO 8601 format
activityActor The email address of the authenticated user who initiated the action, if any.
product[id] The custom code for the product account
product[code] Your custom code for the product account
product[name] The name of your product account
product[subdomain] Your subdomain, if any.
customer[id] Cheddar's unique id for the customer
customer[code] Your custom code for the customer
customer[key] Customer key hash (primarily for constructing a link to hosted update/status)
customer[gatewayToken] The gateway reference for this customer, if any
customer[firstName] Customer given name
customer[lastName] Customer family name
customer[email] Customer email address
customer[company] Customer's company
customer[notes] Notes regarding this customer
customer[isTaxExempt] Flag (1,0) indicating tax exemption status
customer[taxNumber] Customer's tax number, if any
customer[firstContactDatetime] The moment the customer first contacted you
customer[referer] The refering URI for the customer
customer[campaignSource] (utm_source)
customer[campaignMedium] (utm_medium)
customer[campaignTerm] (utm_term)
customer[campaignContent] (utm_content)
customer[campaignName] (utm_campaign)
customer[createdDatetime] The moment this customer was created in Cheddar
subscription[id] Cheddar's unique id for the subscription
subscription[gatewayToken] Gateway ref for this subscription, if any
subscription[method] The payment method type ('none', 'cc', 'paypal', or 'apple')
subscription[ccType] The credit card type, if any (visa, mc, disc, amex, diners, jcb)
subscription[ccLastFour] Last 4 digits of credit card, if any
subscription[ccFirstName] Billing first name (given)
subscription[ccLastName] Billing last name (family)
subscription[ccEmail] Billing email (paypal only)
subscription[ccExpirationDate] Payment method expiration date, if any
subscription[ccCompany] Billing company
subscription[ccCountry] Billing country
subscription[ccAddress] Billing address
subscription[ccCity] Billing city
subscription[ccState] Billing state/province
subscription[ccZip] Billing postal code
subscription[canceledDatetime] The moment of cancelation, if any
subscription[cancelType] The cancel type, if any (unknown, declined, expired, paypal-wait, customer)
subscription[cancelReason] Description of reason for cancelation, if any
subscription[createdDatetime] Moment of subscription creation
subscription[plan][id] Cheddar's unique id for the plan
subscription[plan][code] Your custom code for the plan
subscription[plan][name] Plan name
subscription[plan][description] Plan description
subscription[plan][isActive] Flag (1,0) for the plan
subscription[plan][isFree] Flag (1,0) indicating whether or not the plan is free
subscription[plan][billingFrequencyUnit] (months, days, none)
subscription[plan][billingFrequencyQuantity] Billing frequency per unit
subscription[plan][recurringChargeCode] Your code for the flat recurring charge
subscription[plan][recurringChargeAmount] Amount of the flat recurring charge
subscription[plan][setupChargeCode] Your code for the flat setup fee charge
subscription[plan][setupChargeAmount] The setup charge amount
subscription[plan][createdDatetime] The moment the plan was created
subscription[plan][items][<n>][id] Cheddar's unique id for the item
subscription[plan][items][<n>][code] Your custom code for the item
subscription[plan][items][<n>][name] Item name
subscription[plan][items][<n>][quantityIncluded] Quantity of the item included in the plan
subscription[plan][items][<n>][isPeriodic] Flag (1,0) indicating if Cheddar resets item quantity to zero to start a billing period
subscription[plan][items][<n>][overageAmount] The amount charged for overage, if any
subscription[invoice][id] Cheddar's unique id for the invoice
subscription[invoice][invoiceNumber] Invoice number sequence
subscription[invoice][type] Invoice type (subscription, setup, one-time)
subscription[invoice][billingDatetime] The billable moment for the invoice
subscription[invoice][previousBillingDatetime] The date and time of the last billable invoice if applicable. The billing period is between `billingDatetime` and `previousBillingDatetime`.
subscription[invoice][paidTransactionId] Cheddar's unique id for the transaction which "paid" this invoice
subscription[invoice][taxRate] Tax rate for this invoice
subscription[invoice][isInitial] Flag (1,0) indicating whether or not this is the initial recurring invoice
subscription[invoice][createdDatetime] The moment this invoice was created
subscription[invoice][items][<n>][id] Cheddar's unique id for the item
subscription[invoice][items][<n>][code] Your custom code for the item
subscription[invoice][items][<n>][name] Item name
subscription[invoice][items][<n>][quantity] The customer's quantity of this item as of the hook moment
subscription[invoice][charges][<n>][id] Cheddar's unique id for the charge
subscription[invoice][charges][<n>][code] Charge code for the charge
subscription[invoice][charges][<n>][type] Charge type (custom, setup, recurring, item)
subscription[invoice][charges][<n>][quantity] Charge quantity
subscription[invoice][charges][<n>][eachAmount] Charge amount for each quantity
subscription[invoice][charges][<n>][description] Charge description
subscription[invoice][charges][<n>][createdDatetime] Creation date of the charge
subscription[invoice][transaction][id] Cheddar's unique id for the transaction
subscription[invoice][transaction][parentId] Cheddar's unique id for the parent transaction, if any (if this is a refund)
subscription[invoice][transaction][gatewayToken] Gateway reference for this transaction
subscription[invoice][transaction][amount] Transaction amount (including tax, if any)
subscription[invoice][transaction][taxAmount] Amount of tax, if any
subscription[invoice][transaction][memo] Transaction memo
subscription[invoice][transaction][response] Transaction status (approved, declined, failed, error, voided)
subscription[invoice][transaction][responseReason] Description of the reason for the status
subscription[invoice][transaction][transactedDatetime] The moment this transaction was transacted

5.1.2 Hook-specific Supplemental Data

5.1.2.1 Subscription Changed

The Subscription Changed hook includes the previous subscription information in addition to the data common to all hooks:

Name Description
previousSubscription[id] Cheddar's unique id for the subscription
previousSubscription[gatewayToken] Gateway ref for this subscription, if any
previousSubscription[ccType] The credit card type, if any (visa, mc, disc, amex, diners, jcb)
previousSubscription[ccLastFour] Last 4 digits of credit card, if any
previousSubscription[ccFirstName] Billing first name (given)
previousSubscription[ccLastName] Billing last name (family)
previousSubscription[ccEmail] Billing email (paypal only)
previousSubscription[ccExpirationDate] Payment method expiration date, if any
previousSubscription[ccCompany] Billing company
previousSubscription[ccCountry] Billing country
previousSubscription[ccAddress] Billing address
previousSubscription[ccCity] Billing city
previousSubscription[ccState] Billing state/province
previousSubscription[ccZip] Billing postal code
previousSubscription[canceledDatetime] The moment of cancelation, if any
previousSubscription[cancelType] The cancel type, if any (unknown, declined, expired, paypal-wait, customer)
previousSubscription[cancelReason] Description of reason for cancelation, if any
previousSubscription[createdDatetime] Moment of subscription creation
previousSubscription[plan][id] Cheddar's unique id for the plan
previousSubscription[plan][code] Your custom code for the plan
previousSubscription[plan][name] Plan name
previousSubscription[plan][description] Plan description
previousSubscription[plan][isActive] Flag (1,0) for the plan
previousSubscription[plan][isFree] Flag (1,0) indicating whether or not the plan is free
previousSubscription[plan][billingFrequencyUnit] (months, days, none)
previousSubscription[plan][billingFrequencyQuantity] Billing frequency per unit
previousSubscription[plan][recurringChargeCode] Your code for the flat recurring charge
previousSubscription[plan][recurringChargeAmount] Amount of the flat recurring charge
previousSubscription[plan][setupChargeCode] Your code for the flat setup fee charge
previousSubscription[plan][setupChargeAmount] The setup charge amount
previousSubscription[plan][createdDatetime] The moment the plan was created
previousSubscription[plan][items][<n>][id] Cheddar's unique id for the item
previousSubscription[plan][items][<n>][code] Your custom code for the item
previousSubscription[plan][items][<n>][name] Item name
previousSubscription[plan][items][<n>][quantityIncluded] Quantity of the item included in the plan
previousSubscription[plan][items][<n>][isPeriodic] Flag (1,0) indicating if Cheddar resets item quantity to zero to start a billing period
previousSubscription[plan][items][<n>][overageAmount] The amount charged for overage, if any

5.2 Security

Webhooks contain sensitive customer information. While hooks never include a customer's full credit card number, they do contain some payment information (ccLastFour, ccType, billing address) and personally identifiable information (name and email address). Before you enable hooks, you'll want to take a few steps to ensure that your hook data and listeners are protected from potential security vulnerabilities.

5.2.1 Use SSL

You may use an HTTP or an HTTPS URL, but we strongly recommend using an HTTPS URL to secure your hook data in transit and protect against replay attacks for example.

5.2.2 Request Signature Verification

Hook requests are signed for additional security. You may wish to validate a request's signature to ensure that the hook is coming from Cheddar and is well-formed. This is not a requirement but is highly recommended. HTTP POST requests from Cheddar's Custom URL hooks include a special header: X-CG-SIGNATURE. The value of this header is an HMAC sha256 keyed hex hash of an MD5 hash of the request body using your product secret key as the key.

Here are the generic steps to validate a request:

  1. Get the raw body of the request
    • This is the raw content of the HTTP POST request not including the headers
  2. Calculate the MD5 of the raw request body (we refer to this as the "request token")
    • The MD5 hash should be a 32-character hexadecimal number
  3. Use the sha256 algorithm to generate an HMAC hash of the request token
    • use your product secret key as the salt
    • The hash should result in a 64-character hexadecimal number
  4. Compare the result from step 3 to the value of the X-CG-SIGNATURE header in the request.
    • If they match, the request can be considered well-formed and from the expected source.

You can find your product secret key here. The key is called a secret key for a reason: it should be kept a secret. It is up to you to protect your secret key.

3.2.2.1 A Ruby example for validating a request:

3.2.2.2 A raw PHP example for validating a request:

Note that in PHP the super global $SERVER keys are the header names altered to be prepended with `HTTP` and dashes are underscores.

3.2.2.3 A basic Zend Framework 1 controller for handling hooks:

3.2.2.4 A basic C# example for validating a request:

3.2.3 X-CG-TOKEN Header

You may have noticed that there is also an X-CG-TOKEN header in hook requests. This header is provided as a convenience. It is the value of the request MD5 hash as calculated prior to request transit. This value should not be used in a production environment for validation of a request. It is provided so that you may compare it to your own calculation of the request hash while in development of your hook listener. Using the value of this header for validation rather than calculating the request token in your listener make a man-in-the-middle attack possible.

3.2.4 Restrict by IP

If you'd like to ensure that hooks are coming from Cheddar's IPs, you can do that, too. Currently, Cheddar uses the following IPs. These are subject to change. If they do, we'll let you know via email, in-app message, or by posting on our status page.

  • 3.210.189.123
  • 54.89.51.187
  • 146.88.119.59
  • 198.90.23.194
  • 198.90.23.195
  • 198.90.23.190
  • 198.90.23.192
  • 198.90.21.112
  • 162.218.137.254

5.3 Testing

5.3.1 See a Post

One of the easiest ways to test a hook is using a basic POST receiver like PostCatcher. Set up a bin, configure the URL in Cheddar, then cause an event to happen in your Cheddar account.

5.3.2 Rerunning Hooks

Often it's useful to trigger resending the same hook payload multiple times for development purposes. You can use the Hooked Activity Log to manually resend (or stop automatic retries) of individual events or events in bulk.

5.3.3 Testing in Your Development Environment

If you’d like to test webhook functionality within your app in a development environment, make sure your webhook endpoint is available on the public internet (Cheddar needs to send hooks to a public location). We recommend you use a tunneling service, such as Ngrok, to make your endpoint publicly available if you’re developing on your local machine.

6 Fault Tolerance, Retries, and Reporting

Hooked events are reported within your Cheddar dashboard in your Hooked Activity log. Information is available to you via this searchable interface that doubles as a workspace for manipulating individual hooks or in bulk.

6.1 Affirmative Response

Your hook listener must respond with an HTTP status of 200-299. If a hook listener responds with an HTTP status code of < 200 or >=300 (or does not respond), the hook is considered to have failed and will be automatically reissued.

It's important to note that if your hook listener throws a 404, Cheddar will consider the hook failed and retry it later. Often a 404 can mean that a dependent entity is not found when processing the hook. Depending on your listener configuration, it could be that this is a normal condition and the hook processing is actually successful. If so, your listener should return a >=200 response status to prevent unnecessary retries.

6.1.1 Timeouts

Hooks are set with a connect timeout of 10 seconds and a read timeout of 30 seconds. That means that if your hook listener doesn't respond within the timeout period, it will be considered a failure with result "Unable to connect" or "Read timed out" in your hooked activity log and it will be retried. If you expect your listener to take more than 10+30 seconds to respond during normal processing, you might consider issuing the response before your processing is complete. Or, do some background processing of lengthy jobs. Or, make your hook tolerant of the retries.

6.2 Automatic Retries

Failed hooks are automatically retried on an exponential backoff schedule. After 16 total attempts over approximately 18 hours, the hook will be marked as "fatal". If a hook fails too many times, it will be auto-disabled. You may manually reenable a hook but any events occurring between auto-disable and reenable cannot be rerun.

6.2.1 Idempotence

Due to the potential for retries as mentioned, it is highly recommended that any logic executed in your hook listener is idempotent. In short, you'll want to make your listener logic tolerant of any retry (unexpected or otherwise) so that you do not have any adverse effects of your logic running more than once.

6.3 Manual Retries and Canceling Retries

Cheddar includes a hooked activity log for you to manually rerun a hook or cancel automatic retries. The hooked activity log can be found here.

Any hook may be retried manually no matter its current state. You may also cancel or stop automatic retries for an individual hook event or in bulk by marking a hook or hooks as "complete" or "fatal".

View Plans and Pricing   or   Get Started with Cheddar now →

Recent Discussions

28 Mar, 2024 10:45 PM
24 Jan, 2024 08:33 AM
11 Jan, 2024 07:13 AM
30 Nov, 2023 02:07 AM
22 Nov, 2023 08:41 AM