> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dintero.com/llms.txt
> Use this file to discover all available pages before exploring further.

<AgentInstructions>

## Submitting Feedback

If you encounter incorrect, outdated, or confusing documentation on this page, submit feedback:

POST https://docs.dintero.com/feedback

```json
{
  "path": "/docs/checkout/validating-callbacks",
  "feedback": "Description of the issue"
}
```

Only submit feedback when you have something specific and actionable to report.

</AgentInstructions>

# Validating callbacks

> Open firewalls for Dintero callback IPs and verify the authenticity of incoming Checkout callbacks so only legitimate session events update your backend.

## Opening firewalls for callbacks

Callbacks from checkout sessions will be sent from one of these IPs:

* `34.241.230.119`
* `34.242.13.162`

If you're using a firewall, traffic from this IP should be let through.

## Validating payload with signature

Use [POST /v1/admin/signature](/checkout-api.html#operation/admin_signature_post) to create a secret.

Callbacks from Dintero will now include a header named **Dintero-Signature**, and your backend can now implement signature
verification for this.

### Example code for validating signature

To validate the signature received in the **Dintero-Signature** header

* Note that spaces in query parameters must be encoded with `+` (not `%20`) before
  the signature is created
* The query parameters must be sorted

```js theme={null}
const assert = require("node:assert/strict");
const crypto = require("node:crypto");
const account_id = "T12345678";
const secret = "apikeysecret";

const createSignature = (requestUrl, method, timestamp) => {
    const dataUrl = new URL(requestUrl);
    const { hostname, pathname } = dataUrl;

    const params = dataUrl.searchParams;
    params.sort();

    const query = params.toString();
    const payload =
        `${timestamp}\n${account_id}\n${method}` +
        `\n${hostname}\n${pathname}\n${query}`;
    const signature = crypto
        .createHmac("sha256", secret)
        .update(payload, "utf8")
        .digest("hex");
    return `t=${timestamp},` + `v0-hmac-sha256=${signature}`;
};

const verifySignature = (signatureHeader, method, requestUrl) => {
    const parts = signatureHeader.split(",");
    const timestamp = parseInt(parts[0].split("=")[1]);
    assert.ok(
        // expire after 5 minutes
        timestamp < Math.floor(new Date().getTime() / 1000 + 5 * 60 * 60),
    );

    const trusted = Buffer.from(
        createSignature(requestUrl, method, timestamp),
        "ascii",
    );
    const untrusted = Buffer.from(signatureHeader, "ascii");
    assert.ok(crypto.timingSafeEqual(trusted, untrusted));
    console.log("signature valid");
};
```

## How to view the callback sent and received

Sometimes, small unforeseen difficulties might occur when implementing the signature check.
For example, if you successfully create a transaction from a checkout session but the signature check fails on the received callback, this might be for you.

To provide a better overview of the request sent and response received, the Backoffice platform offers a view at the bottom of each individual transaction page. This view includes any callbacks sent and received.

#### 1. Login to [backoffice](https://backoffice.dintero.com/), then follow this interactive slide-show

<div style={{ position: 'relative', paddingBottom: 'calc(57.7714012434242% + 41px)', height: 0, width: '100%' }}>
  <iframe src="https://demo.arcade.software/Zo6CYKuX4eqiqJBFmdzf?embed" title="Dintero Backoffice" frameBorder="0" loading="lazy" webkitAllowFullScreen mozAllowFullScreen allowFullScreen allow="clipboard-write" style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', colorScheme: 'light' }} />
</div>
