Link
✎

PayKickstart Licensing Integration

In short: PayKickstart posts form-encoded IPNs with an HMAC-SHA1 hash. The sales event fires for every successful transaction, including rebills, so your receiver creates one license per transaction and deactivates it on cancellation or refund.

PayKickstart calls the IPN URL you set on a product when something happens. Each product needs its own IPN URL (you can add several), and you choose whether it fires on all events or on specific events.

What PayKickstart sends

PayKickstart sends an HTTP POST as application/x-www-form-urlencoded. Documented fields include buyer_email, buyer_first_name, buyer_last_name, transaction_id, invoice_id (the purchase id), product_id, product_name, campaign_id, tracking_id, transaction_time, mode (live or test) and payment_processor.

Map PayKickstart events to NetLicensing

PayKickstart event What to do in NetLicensing
sales Fires for every successful transaction, including subscription rebills. Create the licensee from buyer_email the first time, and one license per transaction, numbered with transaction_id
subscription-created No license: the payment arrives as sales
subscription-payment Fires for each subscription transaction (is_rebill marks renewals). sales already covers the payment, so create no license here; if you prefer this event for subscriptions, ignore sales for them, never use both
subscription-updated, subscription-changed Create a license from the new template and deactivate the old one
subscription-pause, subscription-unpaused Deactivate on pause; reactivate on unpause
subscription-cancelled, subscription-completed, refund Deactivate the license (active=false)
subscription-pending-cancelation Cancellation at the end of the period: deactivate at period end (subscription-pending-cancellation-revoked reverses it)
subscription-payment-failed Your choice: keep access during the platform’s retry period, or deactivate

PayKickstart documents no event named rebill or cancel: use subscription-payment and subscription-cancelled. Further events exist for trials, leads and fulfilment status.

Check that the request comes from PayKickstart

The request contains a hash field. Remove hash and verification_code, drop empty values, sort the remaining keys alphabetically, join the values with |, and compute an HMAC-SHA1 hex digest with your IPN secret key. The secret is unique to each campaign (campaign_id tells you which one). PayKickstart’s PHP, JavaScript and Python examples differ slightly in which values they drop (the JS and Python versions also drop "0", 0 and null), so copy one example and use it consistently.

Retries and duplicates

An IPN has a 20 second timeout in total (5 for the connection, 15 for the request). PayKickstart tries up to 13 times to get a positive response. After the last failed retry the IPN URL is suspended until you edit and save it again, so monitor it. Events may not arrive in the order they happened.

Match the customer and the plan

buyer_email identifies the customer and product_id the product: map it to your licenseTemplateNumber. The documentation lists no subscription id; invoice_id is the purchase id. Fields starting with custom_ carry GET variables of the checkout page URL: ?var1=123 arrives as custom_var1, so you can pass your NetLicensing licensee number or template number through the checkout link.

Whatever ids you pick, use them as the NetLicensing numbers so later events can address the licensee and license directly and retries cannot create duplicates; see Use the platform’s IDs as NetLicensing numbers.

Example: the calls

PayKickstart                Your receiver                 NetLicensing
|                           |                             |
| sales IPN --------------->|                             |
|                           | verify signature            |
|                           | POST /licensee ------------>|
|                           |  number=email               |
|                           | POST /license ------------->|
|                           |  number=transaction_id      |
|< 2xx ---------------------|                             |
|                           |                             |

The values below are illustrative; field names follow the vendor documentation listed under Sources. Form-encoded bodies are shown decoded for readability. Code samples are Python, using only the standard library unless noted.

1. PayKickstart calls your receiver

POST /webhooks/paykickstart HTTP/1.1
Content-Type: application/x-www-form-urlencoded

event=sales&mode=live&buyer_email=jane%40example.com&buyer_first_name=Jane&buyer_last_name=Doe&transaction_id=5567&invoice_id=PK-123&product_id=42&campaign_id=7&hash=<hex HMAC-SHA1>

2. Your receiver checks the request

import hashlib, hmac

from urllib.parse import parse_qsl

def verify_paykickstart(raw_body: bytes, ipn_secret: str) -> bool:
    fields = dict(parse_qsl(raw_body.decode(), keep_blank_values=True))
    received = fields.pop("hash", "")
    fields.pop("verification_code", None)
    data = "|".join(v for k, v in sorted(fields.items()) if v != "")
    expected = hmac.new(ipn_secret.encode(), data.encode(), hashlib.sha1).hexdigest()
    return hmac.compare_digest(expected, received)

This follows the rule described above. PayKickstart’s own JavaScript and Python examples also drop "0" values; pick one of its examples and keep it consistent. The secret is per campaign (campaign_id).

3. Your receiver calls NetLicensing

NLIC=https://go.netlicensing.io/core/v2/rest
AUTH="apiKey:$NETLICENSING_API_KEY"    # API key with ROLE_APIKEY_OPERATION

# First sales event: the buyer's email becomes the licensee number
curl --user $AUTH --header "Accept: application/json" \
  --data "productNumber=PQVJQ5F7H&number=jane%40example.com&name=Jane%20Doe" \
  $NLIC/licensee

# sales (initial or rebill): one license per transaction_id
curl --user $AUTH --header "Accept: application/json" \
  --data "number=pk-5567&licenseeNumber=jane%40example.com&licenseTemplateNumber=EUJK1BXQ52" \
  $NLIC/license

# refund, or subscription-cancelled with paid time left
curl --user $AUTH --header "Accept: application/json" \
  --data "active=false" \
  $NLIC/license/pk-5567

PQVJQ5F7H and EUJK1BXQ52 stand for your product and license template numbers. A create with a number that already exists returns HTTP 400 with DuplicateEntityException. That makes both calls safe to repeat: send the licensee create with every paid event and continue when it reports a duplicate, and treat a duplicate license as “already done” and answer the platform with 2xx (see IDs as numbers).

Sources


You run this integration yourself; NetLicensing does not host a PayKickstart connector. The PayKickstart details on this page are based on the sources above, and the NetLicensing calls it relies on were tested against the live API. Vendors change their APIs, so verify the details against the linked pages before you go live. Back to Billing and Commerce Platforms.