Softlemon API Documentation
  • Merchant API
  • Partner API
  • Guides
API basics
    API ConventionsEnvironmentsError HandlingRate LimitsSCA and PSD2SupportChangelog
Integration flows
    Accept a Card PaymentAuthorize Now, Capture LaterRefund a PaymentCharge a Returning CustomerAccept an Alternative PaymentPaysafecard via Skrill: Customer JourneySet Up WebhooksIntegrate as a Partner
Reference
    Merchant Transaction WebhooksTransaction StatusesDuplicate Payment Protection
Integration flows

Set Up Webhooks

This guide takes you from no webhook configuration to a verified endpoint receiving signed events: register your URL, capture the signing secret, send a test ping, choose your events and keep an eye on deliveries. For payload shapes, signature verification code and retry semantics, see the webhook integration guide.

Every request below authenticates with your API key as a Bearer token and requires the webhooks:manage scope. Merchant keys manage their own endpoint (one per merchant). Partner keys manage a linked merchant's endpoint by adding merchant_id: a query parameter on GET requests and a body field on writes.

Step 1: Register your endpoint

Call PUT /api/v1/webhook with the HTTPS URL that should receive events. The same call creates the endpoint on first use and updates it in place afterwards.

curl https://api.sandbox.softlemons.com/api/v1/webhook \ --request PUT \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {YOUR_API_KEY}' \ --data '{ "url": "https://example.com/webhooks/softlemon" }'
JSON
{ "success": true, "message": "Webhook endpoint created successfully", "code": "", "data": { "endpoint": { "id": 12, "merchant_id": 123, "url": "https://example.com/webhooks/softlemon", "is_active": true, "events": null, "has_secret": true, "last_success_at": null, "last_failure_at": null, "consecutive_failures": 0, "created_at": "2026-08-01T10:00:00.000000Z", "updated_at": "2026-08-01T10:00:00.000000Z" }, "secret": "whsec_9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c5b4a39281706f5e4d3c2b1a0" } }

The secret in this response is shown exactly once. It is stored encrypted and can never be read back, so capture it now and store it in your secret manager. You need it to verify the X-Softlemon-Signature header on every delivery. Later updates respond with HTTP 200 and never include the secret. If you lose it, rotate to get a new one.

The URL must use HTTPS on a publicly resolvable host. URLs with embedded credentials, localhost style hosts or private IP addresses are rejected with HTTP 422.

Step 2: Send a test ping

Confirm reachability and your signature verification before real events flow. The ping is delivered synchronously, signed with your secret and structured like a real event. It never appears in delivery history and does not touch delivery health.

curl https://api.sandbox.softlemons.com/api/v1/webhook/test \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {YOUR_API_KEY}' \ --data '{}'
JSON
{ "success": true, "message": "Ping sent", "code": "", "data": { "success": true, "status_code": 200, "duration_ms": 184, "error": null } }

The HTTP status of this response is 200 whether or not your receiver answered. Check data.success for the outcome: true means your endpoint answered with a 2xx status. Pings are limited to 10 per minute per API key.

Step 3: Choose your events

By default the endpoint receives every event type except transaction.pending (opt in by listing it explicitly). Send an events list to narrow the subscription:

curl https://api.sandbox.softlemons.com/api/v1/webhook \ --request PUT \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {YOUR_API_KEY}' \ --data '{ "url": "https://example.com/webhooks/softlemon", "events": [ "transaction.captured", "transaction.refunded", "transaction.failed" ] }'
JSON
{ "success": true, "message": "Webhook endpoint updated successfully", "code": "", "data": { "id": 12, "merchant_id": 123, "url": "https://example.com/webhooks/softlemon", "is_active": true, "events": [ "transaction.captured", "transaction.refunded", "transaction.failed" ], "has_secret": true, "last_success_at": "2026-08-09T14:12:03.000000Z", "last_failure_at": null, "consecutive_failures": 0, "created_at": "2026-08-01T10:00:00.000000Z", "updated_at": "2026-08-10T09:30:12.000000Z" } }

Subscription rules:

  • Omit events to keep the stored subscription unchanged.
  • Send "events": null to reset to the default set.
  • An empty list is rejected. To pause deliveries entirely, send "is_active": false instead. The configuration and secret survive a pause.
  • Unsubscribed event types are not recorded at all, so they never appear in delivery history.

The full event catalogue is in the webhook integration guide.

Step 4: Watch your deliveries

GET /api/v1/webhook returns the configuration together with delivery health: last_success_at, last_failure_at and consecutive_failures.

curl https://api.sandbox.softlemons.com/api/v1/webhook \ --header 'Authorization: Bearer {YOUR_API_KEY}'

For per-event detail, list the delivery history. Filters cover status (pending, delivered, failed), event_type, transaction_id and a from/to date range:

curl 'https://api.sandbox.softlemons.com/api/v1/webhook/events?status=failed' \ --header 'Authorization: Bearer {YOUR_API_KEY}'
JSON
{ "success": true, "message": "Webhook events retrieved successfully", "code": "", "data": { "events": [ { "id": "evt_01k20c1w8x4q07pvj5cehm2azs", "event_type": "transaction.refunded", "transaction_id": 123401, "merchant_trans_id": "ORDER-2038", "status": "pending", "attempts": 2, "created_at": "2026-08-09T13:55:10.000000Z", "delivered_at": null, "failed_at": null, "last_attempt": { "delivery_id": "whd_01k20c1wa9t8s7r6q5p4n3m2k1", "attempt": 2, "status_code": 503, "error_reason": "HTTP 503", "response_excerpt": "Service Unavailable", "duration_ms": 912, "is_replay": false, "created_at": "2026-08-09T14:10:11.000000Z" } } ], "pagination": { "current_page": 1, "last_page": 1, "per_page": 25, "total": 1 } } }

List rows never include the payload snapshot. History depth equals the 30 day retention window, older events are pruned.

Step 5: Inspect and replay an event

Fetch a single event to see the stored payload (exactly what was signed and sent) and the full delivery attempt trail:

curl https://api.sandbox.softlemons.com/api/v1/webhook/events/evt_01k20c4x9y5r08qwj6dfhm3bzt \ --header 'Authorization: Bearer {YOUR_API_KEY}'

If your system missed or lost an event, replay it. The replay reuses the same event id and payload, carries a fresh delivery id and adds an X-Softlemon-Replay: true header so your receiver can tell it apart from the original:

curl https://api.sandbox.softlemons.com/api/v1/webhook/events/evt_01k20c4x9y5r08qwj6dfhm3bzt/replay \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {YOUR_API_KEY}' \ --data '{}'
JSON
{ "success": true, "message": "Webhook event replay queued", "code": "", "data": { "event": { "id": "evt_01k20c4x9y5r08qwj6dfhm3bzt", "event_type": "transaction.captured", "transaction_id": 123456, "merchant_trans_id": "ORDER-2041", "status": "delivered", "attempts": 2, "created_at": "2026-08-09T14:11:58.000000Z", "delivered_at": "2026-08-09T14:12:03.000000Z", "failed_at": null, "last_attempt": null } } }

Replaying an already delivered event is allowed, for example when the original was lost downstream. A failing replay never demotes a delivered event. Events older than the 30 day retention window cannot be replayed. Replays are limited to 30 per minute per API key.

Step 6: Rotate the secret

Rotate when the secret may have been exposed or on your own schedule:

curl https://api.sandbox.softlemons.com/api/v1/webhook/rotate-secret \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer {YOUR_API_KEY}' \ --data '{}'
JSON
{ "success": true, "message": "Webhook secret rotated successfully", "code": "", "data": { "endpoint": { "id": 12, "merchant_id": 123, "url": "https://example.com/webhooks/softlemon", "is_active": true, "events": null, "has_secret": true, "last_success_at": "2026-08-09T14:12:03.000000Z", "last_failure_at": null, "consecutive_failures": 0, "created_at": "2026-08-01T10:00:00.000000Z", "updated_at": "2026-08-10T09:30:12.000000Z" }, "secret": "whsec_0a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9" } }

Rotation is a hard cutover: the old secret stops signing immediately and the new one appears exactly once in this response. Update your verifier right away. Deliveries retried after the rotation are signed with the new secret, including retries of events first attempted before it.

Step 7: Delete the endpoint

To stop receiving webhooks for good, delete the endpoint. To pause instead, send "is_active": false with PUT /api/v1/webhook: the configuration and secret survive a pause, and nothing is delivered or retried while it lasts.

curl https://api.sandbox.softlemons.com/api/v1/webhook \ --request DELETE \ --header 'Authorization: Bearer {YOUR_API_KEY}'
JSON
{ "success": true, "message": "Webhook endpoint deleted successfully", "code": "", "data": null }

Deliveries stop immediately. Events still queued for the endpoint are marked failed, and the stored URL and signing secret are erased. Your delivery history stays readable through GET /api/v1/webhook/events. Registering again with PUT /api/v1/webhook creates a new endpoint with a new secret, and a replay of an older event is then delivered to the new endpoint. GET /api/v1/webhook returns HTTP 404 once the endpoint is deleted, and deleting when there is no endpoint returns HTTP 404 as well.

Good to know

  • GET /api/v1/webhook returns HTTP 404 until the endpoint is first created. has_secret only ever reports that a secret exists, never its value.
  • Pause with "is_active": false to stop deliveries while keeping the configuration; DELETE /api/v1/webhook removes the endpoint for good (see Step 7).
  • Partner keys must send merchant_id on every request in this guide. A missing or unlinked merchant_id returns HTTP 400.
  • Build the receiver before you register: verify signatures on the raw request body, answer 2xx within 10 seconds and deduplicate on the event id. Working verification code in five languages is in the webhook integration guide.
Last modified on September 7, 2026
Paysafecard via Skrill: Customer JourneyIntegrate as a Partner
On this page
  • Step 1: Register your endpoint
  • Step 2: Send a test ping
  • Step 3: Choose your events
  • Step 4: Watch your deliveries
  • Step 5: Inspect and replay an event
  • Step 6: Rotate the secret
  • Step 7: Delete the endpoint
  • Good to know
JSON
JSON
JSON
JSON
JSON
JSON
JSON