# Handling callbacks

{% hint style="info" %}
Because of the need to maintain backward compatibility (so that existing clients don't stop working) we **cannot** update the content of the callback payload too often, **we recommend using the callback as a signal that the payment has been processed**.

At the time the callback is received, we recommend making a [Payment Status request](https://streampay.gitbook.io/stream-payment-gateway/api-documentation/broken-reference) to get actual information about the payment.
{% endhint %}

As soon as the user transfers Crypto, you will receive a callback to the URL specified in the integration settings.

Callback contains information about payment such as paymentID, original amount, actual amount, timestamp and signature.

You **MUST** to validate signature to make sure that callback is really sent by **CoinPipe server**.

### Callback Details

<table data-header-hidden><thead><tr><th width="246"></th><th></th></tr></thead><tbody><tr><td>HTTP Method</td><td><code>POST</code></td></tr><tr><td>Content-Type</td><td><code>application/json</code></td></tr><tr><td>Expected response codes</td><td><code>200</code> - <code>299</code> (or redirect but final code <strong>must</strong> be 200-299)</td></tr></tbody></table>

If callback fails status of payment will set to `ERR_CALLBACK`. After it our backend will retry sending callback **every 10 minutes** until receiving success code.

We will try to send a callback within **3 days**, after which the attempts will stop and the status will remain `ERR_CALLBACK`.

### Callback Payload

<table><thead><tr><th width="240.33333333333331">Parameter</th><th width="121">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>payment_id</code></td><td>string</td><td>PaymentID in our system.</td></tr><tr><td><code>amount</code></td><td>string</td><td>Original amount of payment in NEAR.</td></tr><tr><td><code>amount_usd</code></td><td>string</td><td>Original amount of payment in USD. Converted on our side.</td></tr><tr><td><code>received_amount</code></td><td>string</td><td>Actual paid amount in NEAR.</td></tr><tr><td><code>received_amount_usd</code></td><td>string</td><td>Actual paid amount in USD. Converted on our side.</td></tr><tr><td><code>current_datetime</code></td><td>timestamp (<a href="https://datatracker.ietf.org/doc/html/rfc3339">RFC3339</a>)</td><td>Timestamp when callback was sent (not payment processed).</td></tr><tr><td><code>signature</code></td><td>string</td><td>Signature of callback to prove that it was sent by <strong>CoinPipe server</strong>.</td></tr></tbody></table>

### **Validating Signature**

You **MUST** validate the signature on your backend in order to prove that callback was sent by **StreamPayments server**

To calculate the signature you have to build a string that contains a callback payload in the following format:

{% code overflow="wrap" %}

```
Amount={amount};AmountUsd={amount_usd};CurrentDateTime={current_datetime};PaymentID={payment_id};ReceivedAmount={received_amount};ReceivedAmountUsd={received_amount_usd};SecretKey={api_integration_secret_key}
```

{% endcode %}

Where `{api_integration_secret_key}` is the secret key you got when creating API Integration. If you lost it you can re-generate the secret key on the [Shop details page](https://app.coinpipe.finance/merchants).

The resulting string should be hashed using `sha256` algorithm.

### Code examples

{% tabs %}
{% tab title="Python (Flask)" %}

```python
@app.route("/payment/callback", methods=["POST"])
def callback():
    json = request.get_json()
    amount = json.get('amount')
    amount_usd = json.get('amount_usd')
    current_datetime = json.get('current_datetime')
    payment_id = json.get('payment_id')
    received_amount = json.get('received_amount')
    received_amount_usd = json.get('received_amount_usd')
    signature = json.get('signature')

    raw_signature = f"Amount={amount};AmountUsd={amount_usd};CurrentDateTime={current_datetime};PaymentID={payment_id};ReceivedAmount={received_amount};ReceivedAmountUsd={received_amount_usd};SecretKey={API_INTEGRATION_SECRET_KEY}"
    computed_signature = sha256(raw_signature.encode()).hexdigest()
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$rawJson = file_get_contents('php://input');
$payload = json_decode($rawJson, true);

$rawSignature = sprintf(
    'Amount=%s;AmountUsd=%s;CurrentDateTime=%s;PaymentID=%s;ReceivedAmount=%s;ReceivedAmountUsd=%s;SecretKey=%s',
    $payload['amount'],
    $payload['amount_usd'],
    $payload['current_datetime'],
    $payload['payment_id'],
    $payload['received_amount'],
    $payload['received_amount_usd'],
    API_INTEGRATION_SECRET_KEY,
);

$computedSignature = hash('sha256', $rawSignature);
```

{% endtab %}

{% tab title="JavaScript (NodeJs)" %}

```javascript
const crypto = require('crypto');

const server = http.createServer(async (req, res) => {
  const buffers = [];

  for await (const chunk of req) {
    buffers.push(chunk);
  }

  const data = Buffer.concat(buffers).toString();
  const payload = JSON.parse(data);
  const rawSignature = `Amount=${payload['amount']};AmountUsd=${payload['amount_usd']};CurrentDateTime=${payload['current_datetime']};PaymentID=${payload['payment_id']};ReceivedAmount=${payload['received_amount']};ReceivedAmountUsd=${payload['received_amount_usd']};SecretKey=${process.env.API_INTEGRATION_SECRET_KEY}`;
  const computedSignature = crypto.createHash('sha256').update(rawSignature).digest('hex');

  res.end();
})
```

{% endtab %}
{% endtabs %}
