Skip to content

Paddle setup

Keylight integrates with Paddle through a one-way webhook destination: every time a transaction completes, a subscription state changes, or a refund is issued, Paddle posts the event to Keylight and Keylight mints, updates, or refunds the license. There is no OAuth — only the signed webhook plus an API key for resolving customer emails (Paddle doesn’t send them in webhook payloads).

From your dashboard, go to Settings → Integrations → Paddle and click Enable Paddle. Keylight reveals the webhook URL:

https://api.keylight.dev/webhooks/paddle/<your-tenant-id>

Paste this URL into Paddle’s notification settings (next section). The signing secret you’ll paste back into Keylight is what verifies the Paddle-Signature header on every incoming request.

In Settings → Integrations → Paddle, add one row per Paddle Price ID. A Paddle product can have multiple prices (one-time, monthly, annual) — each gets its own row.

Paddle Price IDKeylight appKey type
pri_01h…abcmyapppro
pri_01h…xyzmyappteam-annual

Keylight reads data.items[0].price.id from each event to pick the row. Unmapped Price IDs cause the webhook to 4xx instead of minting against an unknown app.

In the Paddle dashboard:

  1. Go to Developer Tools → Notifications.
  2. Click New destinationWebhook.
  3. Paste the Keylight URL from step 1 into the URL field.
  4. Subscribe to these event types (Keylight ignores anything else):
    • transaction.completed
    • subscription.created
    • subscription.updated
    • subscription.resumed
    • subscription.paused
    • subscription.canceled
    • adjustment.created
  5. Save. Paddle reveals the signing secret — copy it.

Back in Keylight (Settings → Integrations → Paddle), paste the signing secret into the Webhook signing secret field and save.

4. Add your Paddle API key (required for upgrades + emails)

Section titled “4. Add your Paddle API key (required for upgrades + emails)”

Paddle’s transaction webhooks contain a customer_id but not the customer email. Keylight needs the email to mint a license and send it. In the same panel, paste a Paddle API key with read access to Customers:

  1. Paddle dashboard → Developer Tools → Authentication.
  2. Generate a key (Read-only on Customers is sufficient).
  3. Paste it into Keylight → Save Paddle API key. Stored encrypted at rest.

Without this key the integration will reject events with 400 customer_email_unresolvable.

Use Paddle’s Test event button on the webhook destination. Send a transaction.completed test:

  • A 200 OK from Keylight with a fresh license record in Dashboard → Licenses means everything is wired correctly.
  • A 400 invalid_signature means the signing secret in Keylight doesn’t match the one in Paddle — re-copy.
  • A 400 unmapped_price means the test event’s Price ID isn’t in your map.

When a customer completes checkout, Paddle fires transaction.completed → Keylight verifies the Paddle-Signature, resolves the customer email via the Paddle API key, looks up the app+key-type from the Price ID, mints a license, and records the payment. Subscription renewals re-extend the license; subscription.canceled flips it to cancelled at the end of the current period; an adjustment.created refund event triggers a refund.

To send a customer to a Paddle checkout that upgrades their existing license, append custom_data[keylight_upgrade_key]=<license-key> to the Upgrade checkout URL you set on the key type. Paddle echoes custom_data back in the webhook and Keylight links the new transaction to the existing license.

Settings → Integrations → Paddle → Disconnect clears the signing secret, the Paddle API key, and the Price ID map. Existing licenses are untouched — only new webhook deliveries stop minting.