Settings

⚙️

Webhook URL settings

The target URL to which HTTP POST requests will be sent needs to be provided to your integration manager, and confirmation should be received that it has been added to the partner settings on Paybis end.

Available webhooks

1. Verification Status Update

This webhook is called for each case when the user initiates/completes SumSub KYC verification in the widget application.

Webhook messages are sent on the following status update events:

  • started - user initiated the KYC verification process (Sumsub widget is opened on frontend), but the final application status hasn't been yet received from SumSub OR RETRY result is returned (the user is supposed to resubmit the requested documents).
  • approved - KYC application was approved (GREEN result is received from SumSub).
  • failed - KYC application was rejected (RED final reject is received from SumSub).

The webhook is executed using HTTP POST method and contains JSON data with a VERIFICATION_STATUS_UPDATED event inside.

Event parameters:

ParameterDescription
partnerUserIdThe customer's unique ID in the partner's system used in the POST Request endpoint.
statusKYC verification status of the customer with corresponding partnerUserId. Possible values: Started, Approved, Failed.
timestampThe time when the KYC verification status was updated in Unix 10-digit epoch time format.
residenceCountryTwo-letter ISO code of the country where user was verified.

Example webhook payload with Started verification status:

{
  "event": "VERIFICATION_STATUS_UPDATED",
  "data": {
    "partnerUserId":"e18fb964-fd9a-4de7-96c4-u1dq8a1ddd1",
    "status":"started"
  },
  "timestamp":1653593988
}

Example webhook payload with Failed verification status:

If the verification has been failed, the residenceCountry parameter is set to null.

{
  "event": "VERIFICATION_STATUS_UPDATED",
  "data": {
    "partnerUserId":"e18fb964-fd9a-4de7-96c4-u1dq8a1ddd1",
    "status":"failed",
    "residenceCountry": null
  },
  "timestamp":1653593988
}

Example webhook payload with Approved verification status:

Additional parameter residenceCountry is set to the country of the verification.

{
  "event": "VERIFICATION_STATUS_UPDATED",
  "data": {
    "partnerUserId":"e18fb964-fd9a-4de7-96c4-u1dq8a1ddd1",
    "status":"approved",
    "residenceCountry": "LV"
  },
  "timestamp":1653593988
}

📘

Shared access token

If you are using the Shared KYC solution, you can call the /v1/sumsub/shared-token endpoint to retrieve the Shared Access Token for approved applicants. Shared token can be used to import applicant´s KYC data from SumSub.

2. Transaction Status Update

This webhook is sent in the event of transaction status change.

The webhook is executed using HTTP POST method and contains JSON data with a TRANSACTION_STATUS_CHANGED event inside. Webhook messages are sent on the following status update events:

  • started - transaction was created in the Paybis system: it happens when the user confirms or gets the quote on the Exchange form and confirms it (for authenticated users) or when the user logs in after quote confirmation (for non-authenticated users);
  • cancelled - transaction was cancelled by the client on widget UI.
  • rejected - transaction was rejected by PSP or Paybis with the following rejectReason as additional parameter:
    • antifraud-failed - transaction was rejected due to potential fraud detected during security checks.
    • auto-rejected- transaction was automatically cancelled because user did not complete it within the allowed time frame.
    • legal-complience-reject - transaction was rejected due to legal or regulatory restrictions. This usually occurs when there's an issue with the user's Sumsub questionnaire.
    • insufficient-funds - transaction failed due to insufficient funds in the user's account. This is specific to Trustly transactions.
    • account-verification-failed - user needs to verify their account details with customer support before retrying.
    • banned-user - user is banned from making recurring transactions.
    • asset-region-restriction - selected cryptocurrency is not available for transactions in the user's region due to geographical restrictions.
    • payment-not-attempted - transaction was rejected because the user did not complete the payment within the time frame.
    • finprom-regime - transaction was blocked due to regulatory restrictions related to financial promotion.
    • kyc-failed - user's KYC verification failed. The user should update their verification details and resubmit.
    • user-age-restriction - transfer was restricted due to the user's age.
    • security-concerns - transaction was rejected due to security concerns detected by the system.
    • other - transaction was rejected for a reason not specifically categorized.
  • payment-error - technical error occured while processing the payment (more details about payment decline reasons).
  • completed - transaction successfully processed.

❗️

Important: Please be aware that due to the nature of transaction processing, multiple webhooks with the same status might be generated for a single transaction.

It's crucial to ensure your system processes all webhooks, not just the initial one.

📘

You can choose between 2 payload presets when setting up the webhook with your integration manager:

  • default (extended) - contains full transaction details including customer's personal info, such as email address, masked credit card number, billing address, etc.
  • light (no customer's personal data) - does not contain fields with the customer's personal and sensitive data.

Example webhook rejection reason payloads

"transaction": {
	"status": "rejected",
	"rejectReason": "auto-rejected",
	"invoice": "PB24064082956TX95",
	"flow": "buyCrypto",
	"createdAt": "2024-06-09T08:57:13+0000",
	"statusUpdatedAt": "2024-06-10T08:59:24+0000"
                },
"transaction": {
	"status": "rejected",
	"rejectReason": "antifraud-failed",
	"invoice": "PB24064182634TX6",
	"flow": "buyCrypto",
	"createdAt": "2024-06-10T08:52:12+0000",
	"statusUpdatedAt": "2024-06-10T08:53:28+0000"
                },

Example webhook payload (default): Buy crypto transaction (Completed)

{
    "timestamp": 1720609653,
    "event": "TRANSACTION_STATUS_CHANGED",
    "data": {
        "requestId": "676a726d-413d-4b60-ac5b-c2b085913235",
        "partnerUserId": "e18fb964-fd9a-4de7-96c4-us1111",
        "userEmail": "[email protected]",
        "userIp": "88.99.118.140",
        "quote": {
            "quoteId": "3f773be0-af1d-4a84-b112-60f23deaf492",
            "amountTo": {
                "amount": "7.7029922",
                "currency": "XLM-TESTNET"
            },
            "amountFrom": {
                "amount": "5.00000000",
                "currency": "EUR"
            },
            "amountReceived": {
                "amount": "0.63",
                "currency": "EUR"
            },
            "currencyCodeTo": "XLM-TESTNET",
            "currencyCodeFrom": "EUR",
            "fees": {
                "currency": "EUR",
                "network_fee": "0.01",
                "service_fee": "4.36",
                "partner_fee": "2.50",
                "total_fee": "4.37"
            },
            "feesInUsd": {
                "network_fee": "0.01",
                "service_fee": "4.72",
                "partner_fee": "2.70",
                "total_fee": "4.73"
            },
            "directionChange": "from",
            "expiresAt": "2024-07-10T11:22:34+0000"
        },
        "transaction": {
            "status": "completed",
            "rejectReason": null,
            "invoice": "PBQA240710189285TX619",
            "flow": "buyCrypto",
            "createdAt": "2024-07-10T11:05:48+0000",
            "statusUpdatedAt": "2024-07-10T11:07:32+0000"
        },
        "payment": {
            "id": "yourbrand-credit-card",
            "name": "Credit\/Debit Card",
            "card": {
                "source": "direct",
                "cardholderName": "test test",
                "maskedCardNumber": "424242******4242",
                "expirationDate": "05\/2035",
                "billingAddress": {
                    "country": {
                        "name": "Germany",
                        "code": "DE"
                    },
                    "state": null,
                    "zip": "10001",
                    "city": "Test",
                    "address": "Test"
                }
            },
            "errorCode": null
        },
        "payout": {
            "id": "stellar-xlm",
            "name": "Stellar",
            "transaction_hash": "a9a374f2683eba38d2bc7f486a7cf4f92de7025b9278cea5adade77af559ed12",
            "explorer_link": "https:\/\/testnet.steexp.com\/tx\/a9a374f2683eba38d2bc7f486a7cf4f92de7025b9278cea5adade77af559ed12",
            "destinationWalletAddress": "GD7VS6ZXT42GUI6SXUNEMCTEB3ZOVHWTXEC57WP777DINZX5GGIXVJPT"
        },
        "amountFrom": {
            "amount": "5.00",
            "currency": "EUR"
        },
        "amountTo": {
            "amount": "7.7029922",
            "currency": "XLM"
        },
        "promoCode": null
    },
    "meta": {
        "assets": [
            {
                "currency": "XLM",
                "currencyCode": "XLM-TESTNET",
                "displayName": "Stellar Testnet",
                "blockchain": "stellar",
                "network": "testnet",
                "decimals": 7,
                "tokenContract": null,
                "hasDestinationTag": true
            }
        ]
    }
}

Example webhook payload (light): Buy crypto transaction (Started)

📘

Due to the asynchronous nature of generating Payout objects, the destinationWalletAddress field might not be included in the "Started" webhook and will be added to subsequent webhook updates at later stages of the transaction process.

{
    "timestamp": 1704901290,
    "event": "TRANSACTION_STATUS_CHANGED",
    "data": {
        "requestId": "27700131-1c58-4626-a71e-14ef76f82ef1",
        "partnerUserId": "e18fb964-fd9a-4de7-96c4-3",
        "quote": {
            "quoteId": "115e1a85-f6d0-46d1-af51-ec662be8ad79",
            "amountTo": {
                "amount": "0.00749377",
                "currency": "BTC"
            },
            "amountFrom": {
                "amount": "333.00000000",
                "currency": "EUR"
            },
            "amountReceived": {
                "amount": "313.41",
                "currency": "EUR"
            },
            "currencyCodeTo": "BTC",
            "currencyCodeFrom": "EUR",
            "fees": {
                "currency": "EUR",
                "network_fee": "6.30",
                "service_fee": "13.29",
                "partner_fee": "3.33",
                "total_fee": "19.59"
            },
	   "feesInUsd": {
              	"network_fee":"6.74",
              	"service_fee":"14.22",
              	"partner_fee":"3.56",
              	"total_fee":"20.96"
            },
            "directionChange": "from",
            "expiresAt": "2024-01-10T15:56:31+0000"
        },
        "transaction": {
            "status": "started",
            "invoice": "PBQA24011047674TX870",
            "flow": "buyCrypto",
            "createdAt": "2024-01-10T15:40:48+0000",
            "statusUpdatedAt": "2024-01-10T15:41:29+0000"
        },
        "payment": {
            "id": "credit-card",
            "name": "Credit\/Debit Card",
            "card": {
                "source": "direct",
                "billingAddress": {
                    "country": {
                        "name": "Poland",
                        "code": "PL"
                    }
                }
            }
        },
        "payout": {
            "id": "bitcoin",
            "name": "Bitcoin",
            "transaction_hash": null,
            "explorer_link": null,
            "destinationWalletAddress": "tb1q6v5tpkkpqu5r6gwvpa9xh3atnpyvw2cs9talpp"
        },
        "amountFrom": {
            "amount": "333.00",
            "currency": "EUR"
        },
        "amountTo": {
            "amount": "0.00749377",
            "currency": "BTC"
        },
        "promoCode": null
    },
    "meta": {
        "assets": [
            {
                "currency": "BTC",
                "currencyCode": "BTC",
                "displayName": "Bitcoin",
                "blockchain": "bitcoin",
                "network": "mainnet",
                "decimals": 8,
                "tokenContract": null,
                "hasDestinationTag": false
            }
        ]
    }
}

Example webhook payload (light): Buy crypto transaction (Rejected)

{
    "timestamp": 1709119672,
    "event": "TRANSACTION_STATUS_CHANGED",
    "data": {
        "requestId": "800a2eba-bd56-4c25-8345-795fe0711bfc",
        "partnerUserId": "e18fb964-fd9a-4de7-96c4-uk080099",
        "quote": {
            "quoteId": "f89f58a8-9df2-48ed-846c-2b51b738b63d",
            "amountTo": {
                "amount": "0.0057739",
                "currency": "BTC"
            },
            "amountFrom": {
                "amount": "333.00000000",
                "currency": "EUR"
            },
            "amountReceived": {
                "amount": "316.46",
                "currency": "EUR"
            },
            "currencyCodeTo": "BTC",
            "currencyCodeFrom": "EUR",
            "fees": {
                "currency": "EUR",
                "network_fee": "3.25",
                "service_fee": "13.29",
                "partner_fee": "3.33",
                "total_fee": "16.54"
            },
	   "feesInUsd": {
                "network_fee":"3.48",
                "service_fee":"14.22",
                "partner_fee":"3.56",
                "total_fee":"17.70"
            },
            "directionChange": "from",
            "expiresAt": "2024-02-28T11:42:53+0000"
        },
        "transaction": {
            "status": "payment-error",
            "invoice": "PBQA240228229743TX3",
            "flow": "buyCrypto",
            "createdAt": "2024-02-28T11:26:04+0000",
            "statusUpdatedAt": "2024-02-28T11:27:51+0000"
        },
        "payment": {
            "id": "credit-card-coinpayments",
            "name": "Credit\/Debit Card",
            "card": {
                "source": "direct",
                "billingAddress": {
                    "country": {
                        "name": "United Kingdom",
                        "code": "GB"
                    }
                }
            },
            "errorCode": "3DS_FAILED"
        },
        "payout": {
            "id": "bitcoin",
            "name": "Bitcoin",
            "transaction_hash": null,
            "explorer_link": null,
            "destinationWalletAddress": "tb1q6v5tpkkpqu5r6gwvpa9xh3atnpyvw2cs9talpp"
        },
        "amountFrom": {
            "amount": "333.00",
            "currency": "EUR"
        },
        "amountTo": {
            "amount": "0.0057739",
            "currency": "BTC"
        },
        "promoCode": null
    },
    "meta": {
        "assets": [
            {
                "currency": "BTC",
                "currencyCode": "BTC",
                "displayName": "Bitcoin",
                "blockchain": "bitcoin",
                "network": "mainnet",
                "decimals": 8,
                "tokenContract": null,
                "hasDestinationTag": false
            }
        ]
    }
}

Example webhook payload (default): Sell crypto transaction

{
    "timestamp": 1703689069,
    "event": "TRANSACTION_STATUS_CHANGED",
    "data": {
        "requestId": "54ee6211-1b80-4bcb-a41a-b5bcd9d039ff",
        "partnerUserId": "e18fb964-fd9a-4de7-96c4-2222",
        "userEmail": "[email protected]",
        "userIp": "xx.xx.xxx.xxx",
        "quote": {
            "quoteId": "ece57ed8-0c66-4861-be9c-5eadf1ef1f0e",
            "amountTo": {
                "amount": "88.00",
                "currency": "EUR"
            },
            "amountFrom": {
                "amount": "0.00220915",
                "currency": "BTC"
            },
            "amountReceived": {
                "amount": "0.00220915",
                "currency": "BTC"
            },
            "currencyCodeTo": "EUR",
            "currencyCodeFrom": "BTC",
            "fees": {
                "currency": "EUR",
                "network_fee": "0.00",
                "service_fee": "0.00",
                "partner_fee": "0.00",
                "total_fee": "0.00"
            },
	   "feesInUsd": {
              	"network_fee":"0.00",
              	"service_fee":"0.00",
              	"partner_fee":"0.00",
              	"total_fee":"0.00"
            },
            "directionChange": "to",
            "expiresAt": "2023-12-27T15:13:22+0000"
        },
        "transaction": {
            "status": "started",
            "invoice": "PBQA231227426TX172",
            "flow": "sellCrypto",
            "createdAt": "2023-12-27T14:57:48+0000",
            "statusUpdatedAt": "2023-12-27T14:58:16+0000"
        },
        "payment": {
            "id": null,
            "name": "Bitcoin",
            "card": null
        },
        "payout": {
            "id": "apm_bridgerpay_token_io",
            "name": "Instant Bank Transfer",
            "destinationWalletAddress": "098765490"
        },
        "amountFrom": {
            "amount": "0.00220915",
            "currency": "BTC"
        },
        "amountTo": {
            "amount": "88.00",
            "currency": "EUR"
        },
        "promoCode": null
    },
    "meta": {
        "assets": [
            {
                "currency": "BTC",
                "currencyCode": "BTC",
                "displayName": "Bitcoin",
                "blockchain": "bitcoin",
                "network": "mainnet",
                "decimals": 8,
                "tokenContract": null,
                "hasDestinationTag": false
            }
        ]
    }
}

Example webhook payload (light): Sell crypto transaction

{
   "timestamp":1701807494,
   "event":"TRANSACTION_STATUS_CHANGED",
   "data":{
      "requestId":"77451a10-161e-4a9d-a04e-f7e1c0c940ce",
      "partnerUserId":"e18fb964-fd9a-4de7-96c4-cddac",
      "quote":{
         "quoteId":"09cf5965-93d0-489c-aa3e-3c178929ea78",
         "amountTo":{
            "amount":"33.00",
            "currency":"EUR"
         },
         "amountFrom":{
            "amount":"0.0009087",
            "currency":"BTC"
         },
         "amountReceived":{
            "amount":"0.0009087",
            "currency":"BTC"
         },
         "currencyCodeTo":"EUR",
         "currencyCodeFrom":"BTC",
         "fees":{
            "currency":"EUR",
            "network_fee":"0.00",
            "service_fee":"2.07",
            "partner_fee":"1.05",
            "total_fee":"3.12"
         },
	"feesInUsd": {
            "network_fee":"0.00",
            "service_fee":"2.21",
            "partner_fee":"1.12",
            "total_fee":"3.33"
         },
         "directionChange":"to",
         "expiresAt":"2023-12-05T20:33:16+0000"
      },
      "transaction":{
         "status":"completed",
         "invoice":"PBQA231205426TX152",
         "flow":"sellCrypto",
         "createdAt":"2023-12-05T20:16:22+0000",
         "statusUpdatedAt":"2023-12-05T20:18:12+0000"
      },
      "payment":{
         "id":null,
         "name":"Bitcoin",
         "card":null
      },
      "payout":{
         "id":"paybis-credit-card-out",
         "name":"Visa Card",
         "destinationWalletAddress":"ed9ee3bd-50bd-4ab8-889c-df4333ea6cce"
      },
      "amountFrom":{
         "amount":"0.0009087",
         "currency":"BTC"
      },
      "amountTo":{
         "amount":"33.00",
         "currency":"EUR"
      },
      "promoCode":null
   },
   "meta":{
      "assets":[
         {
            "currency":"BTC",
            "currencyCode":"BTC",
            "displayName":"Bitcoin",
            "blockchain":"bitcoin",
            "network":"mainnet",
            "decimals":8,
            "tokenContract":null,
            "hasDestinationTag":false
         }
      ]
   }
}

Event parameters:

ParameterDescription
requestIdID of the request associated with the transaction.
partnerUserIdCustomer's unique ID in the partner's system used in the POST Request endpoint.
userEmailCustomer's email address.
userIpCustomer's IP address.
quoteObject containing information on the quote based on which the transaction was created. See description of the quote properties in the POST Quote endpoint response specification.
Note that quote and transaction amounts may differ if the exchange rate changed after the quote was generated.
transactionObject containing transaction details:
status- transaction status. Possible values: started, cancelled, rejected, completed, payment-error;
invoice - invoice number;
flow- transaction flow type: buyCrypto or sellCrypto;
createdAt - date and time when the transaction was created;
statusUpdatedAt - date and time when the transaction status was assigned.
paymentObject containing payment method info:
id - identifier of the payment method (matches the ID returned in the GET Payment Methods and POST Quote endpoints)
name - payment method name.
card - customer's credit card details:

- source: allows to distinguish between online credit card and mobile payments, possible values: direct, apple_pay, google_pay,
- cardholder name,
- masked credit card number,
- credit card expiration date,
- billing address (country, state, city, street address, postal code),
- errorCode- payment decline reason code (returned only for Rejected transactions with payment attempt). See the list of decline reason codes here.
payoutObject containing payout details:
id - identifier of the payment method (matches the ID returned in the GET Payout Methods and POST Quote endpoints)
name - payout method name;
destinationWalletAddress - client's account address to which the payout has been made;
transaction_hash - unique identifier of the transaction in blockchain;
explorer_link - blockchain explorer link.
amountFromObject containing amount and currency in which the payment was made.
amountToObject containing amount and currencyin which the payout was made.
feesObject containing fees detailization in transaction currency equivalent: network_fee, service_fee, partner_fee, total_fee
feesInUsdObject containing fees detailization in USD equivalent: network_fee, service_fee, partner_fee, total_fee
timestampThe time when the webhook message was sent in Unix 10-digit epoch time format.
promoCodeValue of the applied promo code for the transaction; should be null if no promo code was used.
metaObject containing the digital asset meta data including:

- cryptocurrency name
- cryptocurrency code
- cryptocurrency display name
- blockchain
- network
- decimals (amount precision)
- token contract (for tokens only)
- destination tag

Retry policy

The HTTP 2xx responses indicate that our webhook call was successful. If your server returns any other response, we retry up to 80 times with the exponential backoff (backoff multiplier = 2). After an unsuccessful response, the first retry is made in 10 sec. The maximum delay between the retries is limited to 6 h: when this limit is reached, the multiplier no longer applies.

Security

For your safety we sign each webhook message with the 4096 bit RSA key using the RSASSA_PSS_SHA_512 asymmetric signing algorithm. The signature is encoded to base64 and sent with the original request in the X-Request-Signature header.

Use our public key to verify incoming POST calls.

Production public key:

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv0zlJaY8HC+39L8yacXD
sOz/zGMPWmu3uLj3+rBGsyRk8UHLCtLM7m9Zp7CXNPeN0elJ67R7fIfYzz5j0R9M
f8MPhok4H72eO/gHga+wTuLBz0VpTGWLykVPPM+R+fv0IJW0J3DBaUWo8iYgd62F
SUQwutXFPKGA67zSM7MvKtBdzgE6f2bb6O6XCg8tWyOqHLROGl8T5rAQphUW6UQc
MxO88jAwL64n9Xb0+H6XBtLwlUc/xJhb18Ag4T4OCvdyJU0TT849EJxJb1hGTjHP
ml6bSowhkjIXouwTpqES7MPaVAWmwE4YzS7jBeNiP1wvoa6u0p2esOVIj/9daKDL
He5soYOrq7z6TKWphqW57NI5YHHQ1Mo/W7OezfiZQNueBSv+f9ynF3SlfF5xB+6T
+3xP6MTYwugdB7PMam3J4klwsoeAb6sLlsHbjM2vk0ji2OkZkiv8iPp/eeD52UT2
SFcNmPKY5fYOU+31WSqwIWc4bb8UYzkBrDAFEXcNtOf6w36ma+dnyqhxZpW6ltnf
/gjSEd/nsO/HEG15pbbL8AlX7W9uK5ea4D8uLKWHWzfcVlT3ZLT0/YVKy+sfpC2h
mmxaoKEiHt9OiTK9+zbBsTD4FAtRq0T7EIoCoJCd+8OoOQz4x4p+VTaDi9mAbFd/
8D6LwL35KLfRkkeHsUCnNlkCAwEAAQ==
-----END PUBLIC KEY-----

Sandbox environment public key:

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApR7LLr506sbJjzs5BuBf
Ubu5Efi+fFN3XlGx6wrKimZ5OSSImHOA8T5fRy/teRriD/92+V18pAh6jmMR7r9E
nnIskJ45IwlMbrp6HRQ5GGt2phHxwj31MvkB+JahqDZrJ6GCwWSd/i7gZjizLy03
pxzV1Sw02342pQMtHX8QgwV5j3/J8Btez5bANHZn5Zp9FS9N6pkedOiZWjiSWOFQ
YUk73VhyW5TjXN5MYQ6FlHmPdwm/Qe/x4DZYXLNAMlFL8Tsb3xNkekJiJPKyr0h2
vqmbEdc9WYtaJAilVS6Yt0QOJtymmQsowCbP7mUFW/i7q8ayjrRUyLnzmoR8H+yY
G+B8lcpu7Aqt0lxUTMRm5KwnTkUyZrimwReWE8LVc68Ae7t4Qxj1dN6nLegDWO7G
BynD7D8ESJ6bNp6GCbc5ntY1T5g+HIGrff7DclcYfzu6RNVgKFlnLxue9J6iJv8q
4wFtn3OM3hxDG/SDk+YUlXiVeUNjPjoA8Z4aEE7OkJBouykLVSiHn4nVrN0WZ1+y
ouYyGwFbL2Vw5G4QR+bi3CZP6rYk9X3A8/xzXjDSYoAqK1+0/7Qncmapbr1Id8qc
huUr+tJq91Ua+EjpdjfaxOrSVBts0iYujY0ahrVCFYBlqu89MSOW4tM4BEgkOeN/
IrZj8Jj85onbaoJr1svCpZUCAwEAAQ==
-----END PUBLIC KEY-----

Signature validation example: node.js

const crypto = require("crypto");

const publicKey = `-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApR7LLr506sbJjzs5BuBf
Ubu5Efi+fFN3XlGx6wrKimZ5OSSImHOA8T5fRy/teRriD/92+V18pAh6jmMR7r9E
nnIskJ45IwlMbrp6HRQ5GGt2phHxwj31MvkB+JahqDZrJ6GCwWSd/i7gZjizLy03
pxzV1Sw02342pQMtHX8QgwV5j3/J8Btez5bANHZn5Zp9FS9N6pkedOiZWjiSWOFQ
YUk73VhyW5TjXN5MYQ6FlHmPdwm/Qe/x4DZYXLNAMlFL8Tsb3xNkekJiJPKyr0h2
vqmbEdc9WYtaJAilVS6Yt0QOJtymmQsowCbP7mUFW/i7q8ayjrRUyLnzmoR8H+yY
G+B8lcpu7Aqt0lxUTMRm5KwnTkUyZrimwReWE8LVc68Ae7t4Qxj1dN6nLegDWO7G
BynD7D8ESJ6bNp6GCbc5ntY1T5g+HIGrff7DclcYfzu6RNVgKFlnLxue9J6iJv8q
4wFtn3OM3hxDG/SDk+YUlXiVeUNjPjoA8Z4aEE7OkJBouykLVSiHn4nVrN0WZ1+y
ouYyGwFbL2Vw5G4QR+bi3CZP6rYk9X3A8/xzXjDSYoAqK1+0/7Qncmapbr1Id8qc
huUr+tJq91Ua+EjpdjfaxOrSVBts0iYujY0ahrVCFYBlqu89MSOW4tM4BEgkOeN/
IrZj8Jj85onbaoJr1svCpZUCAwEAAQ==
-----END PUBLIC KEY-----`;

const message = '{"event":"VERIFICATION_STATUS_UPDATED","data":{"partnerUserId":"e18fb964-fd9a-4de7-96c4-1lclszzd","status":"started"},"timestamp":1654073212}'
var signature = 'jcbM5ysMZuQnUplcBOTqOiPQ3jOsIgl+imMy+AJtbTlvYG3c62WKyYTtm9BvBSuplEvhxOKoe9RBHjYkYsvaOelZr+RcnHkhg1EzEVXfaISJDA6fUyi38uGkWihVnzBjkDvZf7mgpY/4a4q3A+7dN2m5yNQPwPlf/HdExeNQTnrLEANB0rHDa5X091ID5E6vZjccF4/52MkrKdW+9DVbcqT7QLfFwaTxO/E90Aal3tGt/HqE+Ybhw+RocNl14elXeWUm8TtEOn7sr23RxskrBJkuVf68k2zD9zdKiPU7bB94ughqQUbz+6zln8W2F5PugIDkRFbrcigesL1xuR0fRfZJPmqRkaRyy6bZ4mNAisQAo+lBwzQOmowuT+8c/UgS3xU6KT1UF7+W8fj1J4JQ//TjMwWKkYDSpx8fAMGs458jh4+FmrnzFwE9XwXeTDPf38OeREZ7e7AHptyEKfZojjkVbdYtHrQjdqHdkXT35JF23uuItxMEEIEh6jy4STdjHcgl5e1V2N9QNg6V/0Cqax5at60I6oek8iMLgBLnSVOh8DNBSj5Fdt8fQ+kLZj6Q/S+9E9PP2L96Abw9qvexNGpSX2ShgQdkDbe/RsbpN+ORHOfPnnvdzXKsYR4iiVD23GNrsh4QgBd5rbwI7KgloCovpdQhjiyV07g/qBAg+kM';

const verified = crypto.verify(
  'sha512',
  Buffer.from(message),
  {
	key: publicKey,
	padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
  },
  Buffer.from(signature, 'base64'),
)

console.log("Verified:", verified);

Signature validation example: PHP

<?php

use phpseclib\Crypt\RSA;

$publicKey = <<<PUBKEY
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEApR7LLr506sbJjzs5BuBf
Ubu5Efi+fFN3XlGx6wrKimZ5OSSImHOA8T5fRy/teRriD/92+V18pAh6jmMR7r9E
nnIskJ45IwlMbrp6HRQ5GGt2phHxwj31MvkB+JahqDZrJ6GCwWSd/i7gZjizLy03
pxzV1Sw02342pQMtHX8QgwV5j3/J8Btez5bANHZn5Zp9FS9N6pkedOiZWjiSWOFQ
YUk73VhyW5TjXN5MYQ6FlHmPdwm/Qe/x4DZYXLNAMlFL8Tsb3xNkekJiJPKyr0h2
vqmbEdc9WYtaJAilVS6Yt0QOJtymmQsowCbP7mUFW/i7q8ayjrRUyLnzmoR8H+yY
G+B8lcpu7Aqt0lxUTMRm5KwnTkUyZrimwReWE8LVc68Ae7t4Qxj1dN6nLegDWO7G
BynD7D8ESJ6bNp6GCbc5ntY1T5g+HIGrff7DclcYfzu6RNVgKFlnLxue9J6iJv8q
4wFtn3OM3hxDG/SDk+YUlXiVeUNjPjoA8Z4aEE7OkJBouykLVSiHn4nVrN0WZ1+y
ouYyGwFbL2Vw5G4QR+bi3CZP6rYk9X3A8/xzXjDSYoAqK1+0/7Qncmapbr1Id8qc
huUr+tJq91Ua+EjpdjfaxOrSVBts0iYujY0ahrVCFYBlqu89MSOW4tM4BEgkOeN/
IrZj8Jj85onbaoJr1svCpZUCAwEAAQ==
-----END PUBLIC KEY-----
PUBKEY;
$message = '{"event":"VERIFICATION_STATUS_UPDATED","data":{"partnerUserId":"e18fb964-fd9a-4de7-96c4-1lclszzd","status":"started"},"timestamp":1654073212}';
$signature = 'jcbM5ysMZuQnUplcBOTqOiPQ3jOsIgl+imMy+AJtbTlvYG3c62WKyYTtm9BvBSuplEvhxOKoe9RBHjYkYsvaOelZr+RcnHkhg1EzEVXfaISJDA6fUyi38uGkWihVnzBjkDvZf7mgpY/4a4q3A+7dN2m5yNQPwPlf/HdExeNQTnrLEANB0rHDa5X091ID5E6vZjccF4/52MkrKdW+9DVbcqT7QLfFwaTxO/E90Aal3tGt/HqE+Ybhw+RocNl14elXeWUm8TtEOn7sr23RxskrBJkuVf68k2zD9zdKiPU7bB94ughqQUbz+6zln8W2F5PugIDkRFbrcigesL1xuR0fRfZJPmqRkaRyy6bZ4mNAisQAo+lBwzQOmowuT+8c/UgS3xU6KT1UF7+W8fj1J4JQ//TjMwWKkYDSpx8fAMGs458jh4+FmrnzFwE9XwXeTDPf38OeREZ7e7AHptyEKfZojjkVbdYtHrQjdqHdkXT35JF23uuItxMEEIEh6jy4STdjHcgl5e1V2N9QNg6V/0Cqax5at60I6oek8iMLgBLnSVOh8DNBSj5Fdt8fQ+kLZj6Q/S+9E9PP2L96Abw9qvexNGpSX2ShgQdkDbe/RsbpN+ORHOfPnnvdzXKsYR4iiVD23GNrsh4QgBd5rbwI7KgloCovpdQhjiyV07g/qBAg+kM';

$verifier = new \phpseclib\Crypt\RSA();
$verifier->setSignatureMode(RSA::SIGNATURE_PSS);
$verifier->setHash('sha512');
$verifier->setMGFHash('sha512');
$verifier->loadKey($publicKey);

$valid = $verifier->verify(addcslashes($message, '/'), base64_decode($signature));

🚧

Note that you should use version 2.0 of the phpseclib/phpseclib library: phpseclib/phpseclib:^2.