Webhooks
In case you want to perform your own actions when events happen in Moonbase, you can configure webhooks to forward events to your own APIs. Webhooks can be set up to trigger on a number of different events:
- Payment events
OrderPaid
OrderCompleted
OrderPayoutScheduled
OrderRefunded
- Licensing events
LicenseActivated
TrialActivated
To get started with webhooks, head over to your Moonbase account settings, and set up your first webhook:
Once created, it's immediately active and you will have access to the secret key used to compute the signature as described in Security.
Do you have a specific scenario you need webhooks for that is not covered by the current events and content?
Reach out to us through the support channel, or at developers@moonbase.sh.
Security
To ensure that the webhook requests are in fact originating from Moonbase and not some malicious actor, we apply a HMAC-SHA256
algorithm on the body of the request and include this signature in a X-Signature
header on the request.
Example signature verification code
using var algorithm = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
var json = await request.Content.ReadAsStringAsync();
var hash = algorithm.ComputeHash(Encoding.UTF8.GetBytes(json));
var signature = Convert.ToBase64String(hash).ToUpperInvariant();
var sentSignature = request.Headers.GetValues("X-Signature").Single();
Assert.Equal(sentSignature, signature);
Should you ever need to change the secret key, you can do so by editing the webhook.
JSON structure
All webhook requests being sent by Moonbase will have a fixed structure with some basic details about the event that occurred. Additionally, relevant resources are also attached, so that you don't have to query the Moonbase API to fetch more details. The shape of these resources differ between events, and are described on this page.
- Name
id
- Type
- string
- Description
Identifier of this unique webhook request.
- Name
endpoint
- Type
- string
- Description
The endpoint the request is being sent to.
- Name
eventType
- Type
- enum
- Description
The event being communicated, will one of the events listed in this article.
- Name
timestamp
- Type
- string
- Description
Timestamp of the time at which the event occurred.
- Name
resource
- Type
- object
- Description
The resource that the event relates to:
- Name
type
- Type
- enum
- Description
One of:
Order
,License
,Trial
- Name
data
- Type
- object
- Description
The actual contents of the entity. See below for more details about how this is structured.
- Name
customer
- Type
- object
- Nullability
- nullable
- Description
Details about the customer associated with the event. In case the customer is unknown, it will be null.
- Name
id
- Type
- string
- Description
Unique identifier of the customer.
- Name
name
- Type
- string
- Description
Name of the customer.
- Name
email
- Type
- string
- Description
Email address of the customer.
- Name
isDeleted
- Type
- boolean
- Description
Flag showing if the customer account was deleted
Webhook request
{
"id": "a885619a-cb5e-41a6-a07b-1be4e520cccb",
"endpoint": "https://api.my-domain.example/webhook",
"eventType": "OrderCompleted",
"timestamp": "2024-11-11T11:11:11.0000000Z",
"resource": {
"type": "Order",
"data": {...}
},
"customer": {
"id": "92c0f540-9044-4b00-af4c-fe29f5da355e",
"name": "Example customer name",
"email": "user@example.com",
"isDeleted": false
}
}
Payment Events
When customers make purchases through Moonbase, they make them on what we call an "Order". This is why the events related to payments are all prefixed with Order
, and the typical lifecycle of an order goes like this:
- The customer pays for an order, a
OrderPaid
event is sent (not applicable for free purchases) - Moonbase fulfills the order, issuing licenses and sending receipts, completing the order, a
OrderCompleted
event is sent - Moonbase then calculates all affiliate revenue splits and schedules payout for the order, a
OrderPayoutScheduled
event is sent
Lastly, if you chose to refund the order, Moonbase will emit a OrderRefunded
event to any webhook listening.
All events concering orders will have the same shape of the order:
- Name
id
- Type
- string
- Description
Unique identifier of the order.
- Name
status
- Type
- enum(Paid|Completed)
- Description
The current status of the order,
Paid
if not yet completed,Completed
if paid and fulfilled.
- Name
currency
- Type
- string
- Description
The currency used for this purchase.
- Name
completedAt
- Type
- DateTime
- Optionality
- optional
- Description
The timestamp for when the order was completed.
- Name
isRefunded
- Type
- boolean
- Description
Flag indicating if this purchase has been refunded.
- Name
isDisputed
- Type
- boolean
- Description
Flag indicating if this purchase has been disputed.
- Name
total
- Type
- object
- Description
Calculated total for all items part of the order, contains:
original
: The original amount before discountsdiscount
: The total amount of discounts addedsubtotal
: The total amount after discounts have been removedtaxes
: Total taxes to pay, may be inclusive or exclusive of thesubtotal
depending on configuration, currency and region.due
: How much is being paid in total by the customer
- Name
payout
- Type
- object
- Optionality
- optional
- Description
Payout details for this order, only present if an amount is to be paid. Note that this may get updated as affiliate revenue splits are calculated later in the pipeline.
subtotal
: The original amount paid by the customertaxes
: The total amount of taxes collected and remittedplatformFees
: The total amount of fees going to Moonbasedue
: How much is being paid out to you
- Name
billingDetails
- Type
- object
- Description
Billing details about the customer who made the purchase:
- Name
name
- Type
- string
- Description
Full name of the customer.
- Name
businessName
- Type
- string
- Nullability
- nullable
- Description
In case the purchase was a business purchase, this field will have the name.
- Name
taxId
- Type
- string
- Nullability
- nullable
- Description
In case the purchase was a business purchase, this field will have the tax id if given.
- Name
email
- Type
- string
- Description
Email address of the customer.
- Name
phone
- Type
- string
- Nullability
- nullable
- Description
Phone number of the customer. Note that collecting phone numbers is an optional feature in Moonbase and not activated by default.
- Name
address
- Type
- object
- Description
Billing address for the customer. Contains the following properties:
- Name
countryCode
- Type
- string
- Description
ISO 3166-1 alpha-2 two-letter country code.
- Name
streetAddress1
- Type
- string
- Description
First line of the regular street address.
- Name
streetAddress2
- Type
- string
- Optionality
- optional
- Description
Second line of the regular street address.
- Name
postCode
- Type
- string
- Description
Postal code of the address.
- Name
locality
- Type
- string
- Description
Locality of the address, only required if no region is given.
Also known asCity
.
- Name
region
- Type
- string
- Description
Region of the address, only required if no locality is given.
Also known asState
.
- Name
items
- Type
- array
- Description
Collection of items part of the order. Note that this can be either products or bundles, and they are discriminated using the
type
property. Some properties are present on both types, others are shared:- Name
type
- Type
- 'Product'
- Description
Item type discriminator.
- Name
productId
- Type
- string
- Description
The unique ID of the product.
Product line item
- Name
type
- Type
- 'Bundle'
- Description
Item type discriminator.
- Name
bundleId
- Type
- string
- Description
The unique ID of the bundle.
Bundle line item
- Name
quantity
- Type
- number
- Description
The quantity of this item.
- Name
price
- Type
- object
- Description
The original price of the product or bundle.
- Name
total
- Type
- object
- Description
The calculated total for this line item.
- Name
variation
- Type
- object
- Description
Details about the selected pricing variation for this item.
- Name
fulfillment
- Type
- object
- Optionality
- optional
- Description
Details about the license fulfillment for this purchase.
Shared
Order data example
{
"id": "dc0b53f9-4e43-4179-8554-00f2a8228a25",
"status": "Completed",
"currency": "EUR",
"completedAt": "2024-11-11T11:11:11.0000000Z",
"isRefunded": false,
"isDisputed": false,
"total": {
"original": {
"currency": "EUR",
"amount": 10
},
"discount": {
"currency": "EUR",
"amount": 5
},
"subtotal": {
"currency": "EUR",
"amount": 5
},
"taxes": {
"currency": "EUR",
"amount": 5
},
"due": {
"currency": "EUR",
"amount": 5
}
},
"billingDetails": {
"name": "Example User",
"businessName": null,
"taxId": null,
"email": "user@example.com",
"phone": null,
"address": {
"countryCode": "NO",
"streetAddress1": "Utsikten 6",
"streetAddress2": null,
"locality": "Skien",
"region": null,
"postCode": "3718"
}
},
"couponsApplied": [
{
"id": "43396b94-53b4-4901-8e9e-ab1d6ee7d3b5",
"code": "MY-UNIQUE-CODE",
"name": "Half off coupons",
"description": "Thanks for being our customer!",
"discount": {
"type": "PercentageOffDiscount",
"percentage": 0.5
},
"applicableProductIds": [],
"applicableBundleIds": []
}
],
"items": [
{
"type": "Product",
"productId": "example-product",
"quantity": 1,
"price": {
"EUR": 10
},
"total": {
"original": {
"currency": "EUR",
"amount": 10
},
"discount": {
"currency": "EUR",
"amount": 5
},
"subtotal": {
"currency": "EUR",
"amount": 5
},
"due": {
"currency": "EUR",
"amount": 5
}
},
"variation": {
"id": "v802c5",
"name": "Default",
"entitlement": {
"type": "PerpetualLicense"
},
"recurrence": {
"type": "OneOff"
},
"price": {
"EUR": 10
}
},
"fulfillment": {
"type": "License",
"licenseIds": [
"d564a47a-d7f3-48ea-8698-57ad7512b11d"
]
}
}
]
}
Licensing events
We currently expose the following licensing related events:
LicenseActivated
: Happens the first time a license is activated on any deviceTrialActivated
: Happens the first time a trial is started on any device
These events have different resource shapes:
License events
- Name
id
- Type
- string
- Description
Unique identifier of license.
- Name
status
- Type
- enum(Active|Revoked)
- Description
The current status of the license.
- Name
productId
- Type
- string
- Description
The product ID that the license is for.
License data example
{
"id": "5ec722c7-f7d9-441d-83af-69ea634e429b",
"status": "Active",
"productId": "example-product"
}
Trial events
- Name
id
- Type
- string
- Description
Unique identifier of trial.
- Name
status
- Type
- enum(Active|Expired)
- Description
The current status of the trial.
- Name
productId
- Type
- string
- Description
The product ID being trialled.
- Name
lastValidatedAt
- Type
- DateTime
- Description
The time of last validation.
- Name
expiresAt
- Type
- DateTime
- Description
The time at which this trial expires.
Trial data example
{
"id": "7cda66c7d03bd35bac892b97436c33b8",
"status": "Active",
"productId": "example-product",
"lastValidatedAt": "2024-11-11T11:11:11.0000000Z",
"expiresAt": "2025-11-11T11:11:11.0000000Z"
}