Overview

Skipify can send outbound webhooks to any publicly accessible server. When an event is triggered, Skipify will send a webhook notification to the configured endpoint(s) for your merchant account. Your server must respond appropriately, or the webhook retry mechanism will kick in.

📘

Webhook Testing

If you would like to generate a test server URL, you can do this using RequestBin or Mockbin. We do not recommend using these for production traffic.

Webhook Setup

Webhooks can be set up on any Skipify merchant account.

📘

Merchant Account Structure and Webhooks

Decide where your webhooks will be set up if your merchant account structure consists of a parent and child(ren) merchant account. Consult your implementation manager for best practices.

Webhooks set up on the parent merchant account can be set up to receive events for all of its children merchant accounts. Toggle the Enable this subscription to receive events from all associated merchants using Skipifyconfiguration in this case.

The following information is needed to configure your merchant account(s)' webhooks. Specify these to your implementation engineer if you do not yet have access to the merchant portal.

  • The endpoint(s) that Skipify will send webhook(s) to
  • The event(s) that the endpoint(s) need to be subscribed to
  • The email to notify when a webhook has not been sent successfully
  • [Optional] webhook description
  • [Optional] A Merchant Secret which you can specify to trust that the webhook came from Skipify. For PAYMENT_SUCCEEDED and PAYMENT_FAILED events, the secret is sent as the HTTP header X-Skipify-Secret For ORDER_PAYMENT_SUCCEEDED, ORDER_PAYMENT_FAILED, and PAYMENT_REQUEST_EXPIRED events, the secret is sent in the JSON body as the secret field
  • [Optional] custom header key/value pair (i.e. x-api-key) can be set to trust that the webhook came from Skipify

Event Types

Skipify can send the following notifications to your systems:

  • ORDER_PAYMENT_SUCCEEDED - sent when a customer has a successful authorization on an order (applicable to any use case)
  • ORDER_PAYMENT_FAILED - sent when a customer has a failed payment authorization (applicable to any use case)
  • PAYMENT_REQUEST_EXPIRED - sent when a customer clicks on a Paylink payment request that has expired where the customer can no longer make a purchase
  • PAYMENT_SUCCEEDED - sent when a customer has a successful authorization from a Merchant Initiated Transaction
  • PAYMENT_FAILED - sent when a customer has a failed payment authorization from a Merchant Initiated Transaction

Webhook Request

Webhook event requests are sent via POST requests to the URL(s) you specify. When a webhook event is triggered, you will receive a request with the event details.

Below are example request bodies for ORDER_PAYMENT_SUCCEEDED, ORDER_PAYMENT_FAILED, PAYMENT_REQUEST_EXPIRED, PAYMENT_SUCCEEDED, PAYMENT_FAILED, and PAYMENT_CREDENTIALS events:

// Sample for ORDER_PAYMENT_SUCCEEDED:
{
  "eventName": "ORDER_PAYMENT_SUCCEEDED", // The Event that triggered the webhook
  "merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0", // The MerchantId that the event was triggered for
  "payload": { // Specific info for this event
    "pspTransactionId": "35472160", // The TransactionId from the PSP for this event
    "merchantInvoiceId": "MYumberABC123 20240130", // Your unique transaction id. This is the merchantInvoiceId for this event (merchantReference parameter from SDK)
    "paylinkId": "70ca1c7c-f483-42a5-9147-99ea858f8568", // The Skipify paylinkId for this event
    "completedAt": "2024-01-31T18:24:00.000Z", // The Time in UTC when the payment succeeded for this event
    "pspRawResponse": "<CreditSaleResponse.....", // Raw JSON/XML payload returned from PSP for you to parse as needed
    "transactionAmount":112, // Amount authorized for this transaction
     "charges": [ // Charges (fees) included on the order.  Note: these amounts are already included in transactionAmount and orderAmount.
    // If no Charges(fees) were applied on an order, this will be formatted as  "charges": null, 
      { "type": "SURCHARGE_FEE", "amount": 10 },
      { "type": "GENERAL_FEE", "amount": 12 }
    ],
    "skipifyTransactionId": "27c3ac7c-db62-4661-9ccc-287573e50568", // Skipify's internal id for this transaction
    "isPartialAuthorization": false, // Indicates if the amount authorized for this transaction was for only part of the order amount
    "cardBrand": "amex", // Brand of the card used for payment. Possible values: amex, mastercard, visa, discover, unknown(if not recognized by PSPs) 
    "cardLastFour": "0005", // Last four digits of card used for payment
    "isSplitPayment": false,
    "recurringMethodId": "35n3ac7c-db62-5446-9ccc-287573e56578", // nullable, store this recurring payment method id to be used in future transactions
    "isInstallments": false, // true if payment was indicated as an installment
    "isFlexPay": false, // true if payment was paid using Flex Pay
    "paymentMethodType": "card", // value of "bank_account" if Pay By Bank was used
    "orderId": "65b8259b0cd7e1fc5eaf92ba", // The Skipify unique orderId for this event
    "orderAmount": 112, // The amount of the order
    "currencyCode": "USD" // Currency code for this payment 
  },
  "manualRetryId": null, // Reserved for future use
  "merchantSet": { // Information about the merchant this event was for
    "merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0",
    "merchantName": "THE BEST MERCHANT", // The Merchant's Business name in the Skipify system for this event
    "merchantIndustry": "RESTAURANT", // The Industry set on this merchant's profile in the Skipify system
    "topLevelMerchantId": null, // Reserved for future use
    "parentMerchant": null, // Parent Merchant if applicable
    "directLineage": [ // Lists all merchants associate with hierarchy of this merchant
      "c1df84e3-3a1b-489a-9758-e071ad61e8ea",
      "45961295-3540-43cd-82d1-0f09d0aec192"
    ]
  },
  "secret": "abd12345"
}
// Sample for ORDER_PAYMENT_FAILED:
{
  "eventName": "ORDER_PAYMENT_FAILED", // The Event that triggered the webhook
  "merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0", // The MerchantId that the event was triggered for
  "payload": { // Specific info for this event
  	"pspTransactionId": "35472160", // The TransactiondId from the PSP for this event
  	"merchantInvoiceId": "MYMerchantOrderNumberABC123 20240130", // Your unique transaction id. This is the merchantInvoiceId for this event (merchantReference parameter from SDK)
  	"paylinkId": "70ca1c7c-f483-42a5-9147-99ea858f8568", // The Skipify paylinkId for this event
  	"pspRawResponse": "<CreditSaleResponse.....", // Raw JSON/XML payload returned from PSP for you to parse as needed
  	"transactionAmount":112, // Amount attempted to be authorized
  	"charges": [ // Charges (fees) inclded on the order. Note: these amounts are already included in orderAmount.
  // If no Charges(fees) were applied on an order, this will be formatted as "charges": null,
  		{ "type": "SURCHARGE_FEE", "amount": 10 },
  		{ "type": "GENERAL_FEE", "amount": 12 }
  	],
  	"skipifyTransactionId": "27c3ac7c-db62-4661-9ccc-287573e50568", // Skipify's internal id for this transaction
  	"orderId": "65b8259b0cd7e1fc5eaf92ba", // The Skipify unique orderId for this event
  	"cardBrand": "amex", // Brand of the card used for payment. Possible values: amex, mastercard, visa, discover, unknown(if not recognized by PSPs)
  	"cardLastFour": "0005", // Last four digits of card used for payment
  	"isSplitPayment": false,
  	"orderAmount": 112, // The amount of the order
  	"currencyCode": "USD" // Currency code for this payment
  },
  "manualRetryId": null, // Reserved for future use
  "merchantSet": { // Information about the merchant this event was for
  	"merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0",
  	"merchantName": "THE BEST MERCHANT", // The Merchant's Business name in the Skipify system for this event
  	"merchantIndustry": "RESTAURANT", // The Industry set on this merchant's profile in the Skipify system
  	"topLevelMerchantId": null, // Reserved for future use
  	"parentMerchant": null, // Parent Merchant if applicable
  	"directLineage": [ // Lists all merchants associate with hierarchy of this merchant
  		"c1df84e3-3a1b-489a-9758-e071ad61e8ea",
  		"45961295-3540-43cd-82d1-0f09d0aec192"
  	]
  },
  "secret": "abd12345"
}
// Sample for PAYMENT_REQUEST_EXPIRED:
{
  "eventName": "PAYMENT_REQUEST_EXPIRED", // The Event that triggered the webhook
  "merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0", // The MerchantId that the event was triggered for
  "payload": { // Specific info for this event
    "paylinkId": "70ca1c7c-f483-42a5-9147-99ea858f8568", // The Skipify paylinkId for this event
    "merchantInvoiceId": "MYMerchantOrderNumberABC123 20240129 150335", // The merchantInvoiceId for this event
    "total": 51, // The Total Amount of the expired Paylink
    "expiration": "2024-01-31T18:24:00.000Z" // The Time in UTC that the Paylink expired
  },
  "manualRetryId": null, // Reserved for future use
  "merchantSet": { // Information about the merchant this event was for
    "merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0",
    "merchantName": "THE BEST MERCHANT", // The Merchant's Business name in the Skipify system for this event
    "merchantIndustry": "RESTAURANT", // The Industry set on this merchant's profile in the Skipify system
    "topLevelMerchantId": null, // Reserved for future use
    "parentMerchant": "b2sd60-6dd4-4136-88e1-c9e5b670f1ca0", // Parent Merchant if applicable
    "directLineage": [ // Lists all merchants associate with hierarchy of this merchant
      "c1df84e3-3a1b-489a-9758-e071ad61e8ea",
      "45961295-3540-43cd-82d1-0f09d0aec192"
    ]
  },
  "secret": "abd12345"
}
// Sample for PAYMENT_SUCCEEDED:

// Merchant Secret can be found in the X-Skipify-Secret header
// Example header: X-Skipify-Secret: "MySecretValue"

{
  "eventName": "PAYMENT_SUCCEEDED", // The Event that triggered the webhook
  "merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0", // The MerchantId that the event was triggered for
  "payload": { // Specific info for this event
    "pspTransactionId": "35472160", // The TransactionId from the PSP for this event
    "merchantInvoiceId": "MYumberABC123 20240130", // The merchantInvoiceId for this event (merchantReference field from SDK)
    "completedAt": "2024-01-31T18:24:00.000Z", // The Time in UTC when the payment succeeded for this event
    "pspRawResponse": "PENyZWRpdENhcmRTYWxlUm.....", // Base64 encoded Raw JSON/XML payload returned from PSP for you to parse as needed
    "initialAmount":112, // Amount sent to the PSP
    "isPartial": false, // Indicates if the amount authorized for this transaction was for only part of the initialAmount
    "transactionAmount":112, // Amount authorized for this transaction, will be less than the initialAmount in the case of Partial Transactions
    "skipifyTransactionId": "27c3ac7c-db62-4661-9ccc-287573e50568", // Skipify's internal id for this transaction
    "networkType": "amex", // Brand of the card used for payment. Possible values: amex, mastercard, visa, discover, unknown(if not recognized by PSPs) 
    "lastFour": "0005", // Last four digits of card used for payment
    "currencyCode": "USD" // Currency code for this payment
  }
}
// Sample for PAYMENT_FAILED:

// Merchant Secret can be found in the X-Skipify-Secret header
// Example header: X-Skipify-Secret: "MySecretValue"

{
  "eventName": "PAYMENT_FAILED", // The Event that triggered the webhook
  "merchantId": "c1brc8b60-6dd4-4136-88e1-c9e5b670f1ca0", // The MerchantId that the event was triggered for
  "payload": { // Specific info for this event
    "pspTransactionId": "35472160", // The TransactionId from the PSP for this event
    "merchantInvoiceId": "MYumberABC123 20240130", // The merchantInvoiceId for this event (merchantReference field from SDK)
    "pspRawResponse": "PENyZWRpdENhcmRTYWxlUm.....", // Base64 encoded Raw JSON/XML payload returned from PSP for you to parse as needed
    "initialAmount":112, // Amount sent to the PSP
    "transactionAmount":112, // Amount attempted for this transaction, will be less than the initialAmount in the case of Partial Transactions
    "skipifyTransactionId": "27c3ac7c-db62-4661-9ccc-287573e50568", // Skipify's internal id for this transaction
    "networkType": "amex", // Brand of the card used for payment. Possible values: amex, mastercard, visa, discover, unknown(if not recognized by PSPs) 
    "lastFour": "0005", // Last four digits of card used for payment
    "currencyCode": "USD" // Currency code for this payment
  }
}

Webhook Response

Skipify only considers a notification delivered if it receives a timely response with a successful status code. The following conditions must be met:

  • Your endpoint must be reachable at port 443 (HTTPS) (Skipify does not support other ports at this time).
  • Your endpoint must respond within 5 seconds.
  • Your endpoint must respond with a 2XX status code (200, 201, 204, etc). Skipify does not follow redirects or consider them successful responses.

Webhook Retry Mechanism

Skipify automatically retries webhook deliveries when your endpoint doesn’t accept an event. Each event gets up to 15 delivery attempts — one initial delivery plus up to 14 automatic retries — spread over several days.

We stop when your endpoint returns a 2xx response, or when all automatic attempts are used.

Approximate retry schedule

The table below shows estimated wait after each failed attempt before the next try. Early retries are close together; later ones are spaced much farther apart.

AttemptApprox. wait after previous failure
1Immediate (first delivery)
2~30 seconds
3~1 minute
4~2 minutes
5~5 minutes
6~10 minutes
7~15 minutes
8~30 minutes
9~1 hour
10~2 hours
11~4 hours
12~8 hours
13~24 hours
14~48 hours
15~72 hours

These are estimates. Actual timing depends on when each attempt fails and queue scheduling.

While retries are running

  • The event stays pending in the Merchant Portal.
  • Each attempt is logged with timestamp, status, and response details when available.

Failure email

If delivery is still failing, we send one email to the failure notification address on the subscription — typically after the 3rd failed attempt (roughly 1–2 minutes after the first try).

That email is an early warning. Automatic retries continue after it is sent.

When retries are exhausted

If delivery still has not succeeded:

  1. Event marked failed - shown as failed in the Merchant Portal.
  2. Manual retry - retry anytime from the portal; this does not restart the original automatic retry schedule.

Update your endpoint URL, secret, or headers if needed, then retry manually or wait for new events once your system is healthy.


Skipify baner with link to contact us form