> For the complete documentation index, see [llms.txt](https://passimpay.gitbook.io/passimpay-api/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://passimpay.gitbook.io/passimpay-api/webhook-1.md).

# Webhook Withdraw

The notification URL is specified in the platform settings in the personal account.

Toggle 'Enable withdraw webhook' is ON in the platform settings in the personal account.

**After all actions are completed, a response with a 200 status must be returned. Otherwise, there will be 2 additional attempts to resend the notification.**

**Ensure that the signature is verified for security purposes.**

<mark style="color:$danger;">To ensure the security of the integration, you must verify the sender's IP address for every incoming Webhook request.</mark>

<mark style="color:$danger;">Before processing a Webhook, you must confirm that the request originated from an authorized IP address provided by our system. Requests from unknown or unauthorized IP addresses must not be processed.</mark>

### Signature Verification Example

{% tabs %}
{% tab title="Java" %}

```java
@RestController
public class SignatureVerificationController {

    private static final String PLATFORM_ID = "your-platform-id";
    private static final String SECRET = "your-api-key";

    // Helper function to generate HMAC-SHA256 signature
    private String generateSignature(String signatureContract, String secret) throws NoSuchAlgorithmException, InvalidKeyException {
        Mac sha256HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        sha256HMAC.init(secretKey);
        byte[] hash = sha256HMAC.doFinal(signatureContract.getBytes(StandardCharsets.UTF_8));
        StringBuilder result = new StringBuilder();
        for (byte b : hash) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }

   // Platform notification URL
    @PostMapping("/notification")
    public ResponseEntity<String> notificationWebHook(@RequestBody Map<String, Object> body, @RequestHeader HttpHeaders headers) throws NoSuchAlgorithmException, InvalidKeyException, JsonProcessingException {
        // Signature Verification
        ObjectMapper objectMapper = new ObjectMapper();
        String sortedBodyJson = objectMapper.writeValueAsString(body);

        // Generate the signature contract string
        String signatureContract = PLATFORM_ID + ";" + sortedBodyJson + ";" + SECRET;

        // Generate HMAC-SHA256 signature
        String signature = generateSignature(signatureContract, SECRET);

        // Get the signature from the headers
        String receivedSignature = headers.getFirst("x-signature");

        // Compare the generated signature with the received signature
        if (StringUtils.hasText(receivedSignature) && signature.equals(receivedSignature)) {
            return ResponseEntity.ok("Signature is valid");
        } else {
            return ResponseEntity.status(400).body("Invalid signature");
        }
    }
}

```

{% endtab %}

{% tab title="Python" %}

```python
body = request.get_json()

# Platform and secret keys (example placeholders)
platform_id = 'your-platform-id'
secret = 'your-api-key'

# Generate the signature contract string
signature_contract = f'{platform_id};{body};{secret}'

# Generate HMAC-SHA256 signature
signature = hmac.new(secret.encode(), signature_contract.encode(), hashlib.sha256).hexdigest()

# Get the signature from the headers
received_signature = request.headers.get('x-signature', '')

# Compare the generated signature with the received signature
if signature == received_signature:
    return 'Signature is valid', 200
else:
    return 'Invalid signature', 400
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php
// Retrieve the raw JSON body from the request
$json = file_get_contents('php://input');
$body = json_decode($json, true);

// Sort the body
$sortedBody = json_encode($body);

// Platform and secret keys (example placeholders)
$platformId = 'your-platform-id';
$secret = 'your-api-key';

// Generate the signature contract string
$signatureContract = $platformId . ";" . $sortedBody . ";" . $secret;

// Generate HMAC-SHA256 signature
$signature = hash_hmac('sha256', $signatureContract, $secret);

// Retrieve the request headers
$headers = getallheaders();

// Get the signature from the headers
$receivedSignature = $headers['x-signature'] ?? '';

// Compare the generated signature with the received signature
if ($signature === $receivedSignature) {
    echo 'Signature is valid';
    // Proceed with further processing
} else {
    echo 'Invalid signature';
    // Handle the error accordingly
}

```

{% endtab %}
{% endtabs %}

#### Headers

<table><thead><tr><th width="191">Name</th><th width="151">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>x-signature</code></td><td>string</td><td>SHA-256 encrypted signature</td></tr><tr><td><code>Content-Type</code></td><td>string</td><td>application/json</td></tr></tbody></table>

#### Request Body

<table data-full-width="false"><thead><tr><th width="226">Name</th><th width="140">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>The type of callback, for example, <code>withdraw</code></td></tr><tr><td><code>approve</code></td><td>integer</td><td>Withdraw status: <br><strong>0</strong> - wait <br><strong>1</strong> - success <br><strong>2</strong> - error</td></tr><tr><td><code>platformId</code></td><td>integer</td><td>Your Platform ID</td></tr><tr><td><code>paymentId</code></td><td>integer</td><td>Payment ID</td></tr><tr><td><code>addressTo</code></td><td>string</td><td>The recipient’s wallet address to which the funds are being sent.</td></tr><tr><td><code>amount</code></td><td>string</td><td>Amount in cryptocurrency</td></tr><tr><td><code>txhash</code></td><td>string</td><td>The transaction hash in the blockchain system, used to track the transaction.</td></tr><tr><td><code>amountDebited</code></td><td>string</td><td>The definitive amount of funds irrevocably removed from the user's balance to settle the specified transaction.</td></tr><tr><td><code>feeNetwork</code></td><td>string</td><td>Blockchain network fee required for processing the transaction on-chain. This is paid to network validators/miners.</td></tr><tr><td><code>feeService</code></td><td>string</td><td>Service fee charged by the platform for processing the transaction. This fee is retained by the service provider.</td></tr><tr><td><code>transactionId</code></td><td>string</td><td>The transaction ID in the Passimpay system. You can use this ID to check the status of the transaction with the <a href="https://passimpay.gitbook.io/passimpay-api/check-withdraw"><code>withdrawstatus</code></a> method.</td></tr><tr><td><code>orderId</code></td><td>string</td><td>A unique identifier for each withdrawal on your resource. Enter a string with a maximum length of 64 and valid characters 'A-Za-z0-9+/=-:.,'</td></tr><tr><td><code>confirmations</code></td><td>integer</td><td><p>The number of confirmations a transaction has received. This field is used in networks such as Bitcoin, Litecoin, Dogecoin, Bitcoin Cash, and Dash.</p><p>For these networks, the system sends <strong>up to two webhook notifications</strong> for the same transaction:</p><p>• the <strong>first webhook</strong> is sent when the transaction receives <strong>1 confirmation</strong>;<br>• the <strong>second webhook</strong> is sent when the transaction receives <strong>2 confirmations</strong>.</p><p>If a transaction is first detected with <strong>2 confirmations</strong>, the system sends <strong>only one webhook notification</strong> corresponding to the 2-confirmation state. In this case, the webhook for 1 confirmation is not sent.</p></td></tr><tr><td><code>destinationTag</code></td><td>integer</td><td>An additional parameter <code>tag</code> or <code>comment</code>, used in Ripple and TON blockchains.</td></tr></tbody></table>

### Resending Webhook Notifications

You can resend a webhook notification from your personal account by following these steps:

1. Navigate to the transactions section in your personal account.
2. Locate and click on the desired transaction.
3. In the opened window, you will see a field displaying the webhook response.
4. Click the **"Resend"** button to resend the webhook notification.
