External licensing systems

If you have pre-existing software that relies on other licensing systems than Moonbase, you can integrate the two. We support two main paths to achieve this integration:

  1. Using pre-uploaded key codes
  2. Using a HTTP API generator

To make it easier to transition between systems, our HTTP API generator supports several protocols:

  1. A modern JSON-based API integration with HMAC security signatures
  2. Compatibility modes for popular platforms like Fastspring, MyCommerce, DigitalRiver, ShareIt and others

If you are building APIs for your own licensing backend, using our JSON-based integration is highly recommended, but if you are transitioning from other payment providers, our compatibility mode might let you move over without any changes necessary in your backend systems.

Do you have a specific scenario you need to support or other questions?
Reach out to us through the support channel, or at developers@moonbase.sh.

Pre-uploaded key codes

In the case your licensing system can pre-generate arbitrary key codes for activating your software, you may opt to use our key code list feature. To get started with this, simply choose the "Key Codes" generator on your product in Moonbase:

At this point, you may start uploading as many key codes as you wish to be used for future purchases. The product overview will indicate whether or not a product has enough key codes remaining, and it's your responsibility to ensure codes don't run out.

HTTP generator

Using our HTTP generator means that Moonbase will call your API on customer purchases to fulfill the order with licenses. It's important that your API is always available, so that customers will get access to products when they make their payment. The API call has a timeout of 5 seconds, and will retry up to 3 times if a failure code is returned.

Your endpoint should be able to handle the request payload, and return a JSON object with licenses per product:

Request payload

  • Name
    type
    Type
    enum(Order|Voucher|License)
    Description

    The type of fulfillment being requested, Order being purchases, Voucher being voucher redemptions and License being manual license provisioning from the Moonbase app.

  • Name
    reference
    Type
    string
    Description

    A reference to the Order/Voucher/License being fulfilled, this will be unique across all fulfillment requests your backend may receive.

  • Name
    customer
    Type
    object
    Description

    Details about the customer who initiated the fulfillment, it may have the following fields:

    • Name
      id
      Type
      string
      Description

      Globally unique customer ID for this customer.

    • Name
      name
      Type
      string
      Description

      Full name of the customer.

    • Name
      businessName
      Type
      string
      Nullability
      nullable
      Description

      If the customer is a business, this will have the name of the business.

    • Name
      taxId
      Type
      string
      Nullability
      nullable
      Description

      If the customer is a business, this will have the tax ID of the business if given.

    • Name
      email
      Type
      string
      Description

      Email address of the customer, this is always present and used as the login for the customer. Do note that Moonbase supports customers changing the email address of their account.

    • Name
      address
      Type
      object
      Nullability
      nullable
      Description

      The billing address of the customer if given:

      • 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 as City.

      • Name
        region
        Type
        string
        Description

        Region of the address, only required if no locality is given.
        Also known as State.

  • Name
    requests
    Type
    array<object>
    Description

    A list of license requests with objects of the following shape:

    • Name
      productId
      Type
      string
      Description

      The ID of the product that needs licenses.

    • Name
      quantity
      Type
      number
      Description

      The number of licenses that is requested.

    • Name
      expiresAt
      Type
      string
      Nullability
      nullable
      Description

      ISO 8601 timestamp for when the issued licenses should expire. Present for subscriptions and other time-limited products, and omitted for perpetual licenses. This value already includes any grace period configured on the product.

    • Name
      subscription
      Type
      object
      Nullability
      nullable
      Description

      Present when the request fulfills a subscription, and omitted for one-off purchases. It may have the following fields:

      • Name
        subscriptionId
        Type
        string
        Nullability
        nullable
        Description

        The ID of the subscription this license belongs to.

      • Name
        interval
        Type
        enum(Daily|Weekly|Monthly|Quarterly|Yearly)
        Nullability
        nullable
        Description

        The billing interval of the subscription.

      • Name
        currentPeriodEnd
        Type
        string
        Nullability
        nullable
        Description

        ISO 8601 timestamp for the end of the current billing period (the renewal boundary). This does not include any grace period.

      • Name
        licenseExpiresAt
        Type
        string
        Nullability
        nullable
        Description

        ISO 8601 timestamp for when the license actually stops working. For active subscriptions this is currentPeriodEnd plus the configured grace period, and for cancelled subscriptions it equals currentPeriodEnd.

      • Name
        status
        Type
        enum(Active|Cancelled|Expired|Completed)
        Nullability
        nullable
        Description

        The current status of the subscription. An initial purchase is always reported as Active.

      • Name
        currentCycle
        Type
        number
        Nullability
        nullable
        Description

        The number of the current billing cycle of the subscription. Cycles are 1-based, so an initial purchase is cycle 1, the first renewal is cycle 2, and so on.

For perpetual products both expiresAt and subscription are omitted. For subscriptions, an initial purchase reports status as Active and currentCycle as 1, while renewals report the subscription's current values. Treat every subscription field as optional, since each is sent only when it is known.

Request

POST
/your/endpoint
POST https://license-backend.your-domain.example/fulfill
Content-Type: application/json
X-Signature: HNA0AVKUMOF5CXC8GKELYVYTYK37Q4ONGLJEL2TJTGA=

{
    "type" : "Order",
    "reference" : "b28f721c-c29a-4fc4-9153-04f128283c51",
    "customer" : {
        "id" : "2d473e34-fc59-4e6e-9f38-4ad379baa8e9",
        "name" : "John Doe",
        "businessName" : null,
        "taxId" : null,
        "email" : "john.doe@example.com",
        "address" : null
    },
    "requests" : [
        {
            "productId" : "example-product",
            "quantity" : 3,
            "expiresAt" : "2026-07-14T12:44:00Z",
            "subscription" : {
                "subscriptionId" : "f6a3c1e2-9b7d-4c3a-8e21-2b9f0a4d7c11",
                "interval" : "Monthly",
                "currentPeriodEnd" : "2026-07-14T10:44:00Z",
                "licenseExpiresAt" : "2026-07-14T12:44:00Z",
                "status" : "Active",
                "currentCycle" : 2
            }
        }
    ]
}

Expected response

When responding to license requests, your backend should respond with a dictionary where the key is the product ID being fulfilled, and the value an array of licenses to issue to the customer.

Each license returned may either be a string which can contain line feed characters, but should not contain any sort of rich text content or HTML, or a file. In case you return a file object, make sure to include all of the following fields:

  • Name
    fileName
    Type
    string
    Description

    The name of the file being returned, including file extension.

  • Name
    contentType
    Type
    string
    Description

    The MIME type of the file being returned, e.g. application/pdf.

  • Name
    data
    Type
    string
    Description

    The file data, encoded as a Base64 string.

In the example response listed, we return three licenses for the product with ID example-product, where the first two are simple license keys represented as strings, and the third is a text file containing the license key.

It's imperative that the number of values in the list matches the requested quantity of licenses for the given product.

Response

{
    "example-product" : [
        "LICENSE-KEY-1",
        "LICENSE-KEY-2",
        {
            "fileName" : "license-key-3.txt",
            "contentType" : "text/plain",
            "data" : "TElDRU5TRS1LRVktMw=="
        }
    ]
}

Revoking licenses

Besides fulfilling orders, Moonbase can notify your backend whenever a license is revoked, so you can deactivate it in your own system as well. This is optional: when configuring the HTTP generator, set a separate Revocation Endpoint URL. When it's set, Moonbase sends a revocation request to it whenever a license is revoked, either manually from the Moonbase app or automatically when an order is refunded. If you leave the Revocation Endpoint blank, revocations are not forwarded and no action is taken on your backend.

Revocation requests are signed with the same HMAC-SHA256 signature as fulfillment requests (see the Security section below) and are retried up to 3 times on failure. Acknowledge a revocation by returning any 2xx status code; no response body is required. Because Moonbase may retry, your handler should be idempotent.

  • Name
    type
    Type
    enum(License)
    Description

    The type of request, this is always License for revocations.

  • Name
    reference
    Type
    string
    Description

    The ID of the license being revoked.

  • Name
    customerId
    Type
    string
    Description

    The ID of the customer who owns the license.

  • Name
    productId
    Type
    string
    Description

    The ID of the product the license is for.

  • Name
    license
    Type
    string | object
    Description

    The license content originally issued for this license, in the same form your backend returned it during fulfillment: either a string, or a file object with fileName, contentType and data. Use this to identify which license to deactivate.

  • Name
    subscription
    Type
    object
    Nullability
    nullable
    Description

    Present when the revoked license belongs to a subscription, using the same shape as the subscription object on fulfillment requests above. Omitted for one-off licenses.

Revocation request

POST
/your/revocation-endpoint
POST https://license-backend.your-domain.example/revoke
Content-Type: application/json
X-Signature: HNA0AVKUMOF5CXC8GKELYVYTYK37Q4ONGLJEL2TJTGA=

{
    "type" : "License",
    "reference" : "8f2c1b4e-3a6d-4f51-9c7a-1d2e3f4a5b6c",
    "customerId" : "2d473e34-fc59-4e6e-9f38-4ad379baa8e9",
    "productId" : "example-product",
    "license" : "LICENSE-KEY-1",
    "subscription" : {
        "subscriptionId" : "f6a3c1e2-9b7d-4c3a-8e21-2b9f0a4d7c11",
        "interval" : "Monthly",
        "currentPeriodEnd" : "2026-07-14T10:44:00Z",
        "licenseExpiresAt" : "2026-07-14T10:44:00Z",
        "status" : "Cancelled",
        "currentCycle" : 4
    }
}

Security

To ensure your fulfillment and revocation endpoints are secure and safe from request forgery, we attach a signature to every fulfillment and revocation request being sent. This signature is using a HMAC-SHA256 authentication code using the secret set up while configuring the generator in the Moonbase app. Using the raw request body and the secret, you can calculate a signature, and make sure that the signature you calculate is the same as ours.

Example signature verification code

    using var algorithm = new HMACSHA256(Encoding.UTF8.GetBytes(expectedSecret));
    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);

If you're using out compatibility modes for other platforms, security patterns may differ. Reach out to us for more information about maintaining secure endpoints for license fulfillment.

Was this page helpful?