Web hooks are accessed via /api/webhook
.
They represent an asynchronous callback to an external API and are triggered by various events in our site.
They work like this:
You set up your application to subscribe to a particular event type in our system via this API.
Let's say you subscribe to the ReceiptShipped
event.
When this event is triggered and it matches your User id
then we proceed to step 3.
Our system sends an HTTP Post to an endpoint of your choosing via a callback_uri
,
letting you know that the event has occured.
We'll send a signature which is signed using your private APIKey so that you can verify the post is authentic.
The following web hook events are available for you to subscribe to.
Triggered when a Game has been sold. The payload will be as follows:
{ "item" : { "quantity" : 1, "name" : "Adrift", "sku_id" : "361B3436-E1EA-11E4-BB8E-E1C477A16DD8", "price_each" : "28.14", "shop_uri" : "/games/adrift", ... }, "shipping_address" : { "city" : "Madison", "state" : "WI", "country" : "United States", } }
ItemSold
Designer
The id
of a Designer you control.
Triggered when a Receipt has been refunded. The payload posted will be a Receipt object.
ReceiptRefunded
User
Your User id
.
Triggered when a Receipt has been marked shipped. The payload posted will be a Receipt object with _include=shipments
enabled.
ReceiptShipped
User
Your User id
.
Complete details in WebHookProperties.
The unique id for this web hook. It will never change.
webhook
.
The object class in our system that you must have edit access to in order to subscribe to a particular event.
The instance id
of the class that you own.
See the list of Events above for details.
The URL endpoint where the HTTP Post operation will be submitted.
The APIKey id
that will be used to sign the post to prevent third-parties from faking posts to your endpoint.
The methods used to fetch and manipulate web hooks.
GET /api/user/xxx/webhooks
See User for details.
GET /api/webhook/xxx
Required. The unique session id provided by a Session method.
Returns:
{ "id" : "xxx", "event" : "ItemSold", ... }
POST /api/webhook
Required. The unique session id provided by a Session method.
Required. See the list of Events above for details.
Required. See the list of Events above for details.
Required. See the list of Events above for details.
Required. The URL endpoint where the HTTP Post operation will be submitted.
The APIKey id
that will be used to sign the post to prevent third-parties from faking posts to your endpoint.
Returns:
{ "id" : "xxx", "event" : "ItemSold", ... }
PUT /api/webhook/xxx
Required. The unique session id provided by a Session method.
Required. See the list of Events above for details.
Required. See the list of Events above for details.
Required. See the list of Events above for details.
Required. The URL endpoint where the HTTP Post operation will be submitted.
The APIKey id
that will be used to sign the post to prevent third-parties from faking posts to your endpoint.
Returns:
{ "id" : "xxx", "event" : "ItemSold", ... }
DELETE /api/webhook/xxx
Required. The unique session id provided by a Session method.
Returns:
{ "success" : 1 }
Calling this method will cause our servers to process a webhook back to your callback_uri
with a type
of test
.
POST /api/webhook/xxx/test
Required. The unique session id provided by a Session method.
Required. A JSON encoded object.
Returns:
1 || 0
A callback is the HTTP Post operation performed by a web hook to the callback_uri
endpoint that you set when you subscribe to a web hook.
The callback will come to your server in the form of an HTTP POST
with the following form parameters:
The number of seconds since January 1, 1970 UTC. You can use this to determine if the message is close enough to your server's time be considered in tolerance. This can be useful for preventing hackers from sending fake messages your way.
A JSON encoded string of the message object sent from this web hook.
The unique id
of this web hook.
The owner_class
defined as part of this web hook.
The owner_id
defined as part of this web hook.
The event
name defined as part of this web hook.
An object of the original data that we're sending you generated from the event.
Can be one of 4 types: subscribe
, unsubscribe
, data
, test
.
When you first create the web hook. Will have an empty payload
.
When you or the system deletes the web hook. Will have an empty payload
.
When the real event is fired it will be of type data
and the payload
will have real data in it.
When you call the Test
method described above. Will have the payload
you define.
A SHA256 hex encoded HMAC signature. You can use this to verify that the callback came from us.
{ 'hmac' => '02e605c1a27fc8263b8fd187b517df85ef59aab118b71979fbaa20c9e297e290', 'message' => '{"owner_id":"795AD480-328E-11E2-B41A-9E208588C839","event":"OrderShipped","type":"test","payload":{"foo":"bar"},"owner_class":"User", "id" : "9E208588C839-3313-333-331133"}', 'epoch' => '1613851807' }
Once you have an end point exposed to receive these callbacks anybody could send a message your way. To verify it came from us use you can use our HMAC signature. You do that using the following procedure.
Create the signature string oncatenating the epoch
, the character .
, and the message
(leave it as a JSON string) together.
Compute an HMAC with the SHA256 hash function. Use the your private_key
from the APIKey associated with this subscription as the key and used the signature string you created in step 1 as the message.
Compare the output of the HMAC you just generated with the hmac
from the message. Remember that the hmac
we send is hex encoded so yours should be too in order to compare.
You can also check the epoch
we sent you with your local server time to protect against timing attacks.
Just like we expect you to build your application to be tolerant of any outages we may have, we don't expect your app to have 100% uptime either. Therefore web hooks will automatically retry upon failure.
Only an HTTP response code of 200
is considered a success. Anything else is considered a failure. If we receive a 200 then you'll never get the the callback again. If we get anything other than 200 we'll start retrying using the rules below.
The first retry will happen approximately 1 hour after the first failure. The second retry will happen 2 hours after the second failure. The third retry will happen 3 hours after the 3rd failure, and so on. Which means that by the time you get to the fourth retry, 6 hours have elapsed.
That said, subsequent events alter this cascading. For example, if one event has already failed, and another event using the same web hook is triggered and succeeds, then the fail count is reset and subsequent retries of past failures will happen faster. Likewise, if a secondary event using the same web hook fails, then it will increment the fail count and thus the cascade will happen faster. Thus, if you have 5 events happen in rapid succession all using the same web hook then the 5th one will have it's retry delay set to 5 hours before its first retry, because the failure count is attached to the web hook not the instance of the event.
You can check on the status of a web hook by using the Fetch method above. There you can see the failures_since_last_success
property to see how far it has cascaded. Also the date_updated
property will tell you the time of the last retry. You cannot, however, check on the status of the individual event instances. You just have to wait for their delays to fire and run their next attempt.
If you change the properties of a web hook (for example the callback_uri
) before the next retry then the new callback_uri
will be used on the next retry.
After 5 consecutive failures the user that created the web hook will be emailed notifying them of the failures. This only happens in the event of 5 consecutive failures though, so if the fail counter is reset because a callback is successfully processed then no email will be sent.
After 100 consecutive failures the web hook will stop processing retries, and thus will only be attempting to perform callbacks on new events.
After 1000 consecutive failures the web hook will automatically delete itself as it considers your site to be permanently down.