# Secure Callback Endpoint

This document outlines the security mechanisms available for securing callback endpoints in our payment gateway solution. When payment events occur, our system sends callbacks to the client’s backend via HTTP requests. To ensure the integrity, authenticity, and security of these callbacks, we provide three complementary security methods:

1. **Signature Verification in Header**
2. **IP Whitelist**
3. **Transaction Verification via API**

Clients can implement one or more of these methods based on their security requirements.

***

## <mark style="color:blue;">1. Signature Verification in Header</mark>

### <mark style="color:blue;">Overview</mark>

A cryptographic signature is included in the Signature header of each callback request. This signature is generated by hashing the request body in alphabetical order with a secret key using HMAC-SHA256. Clients can verify this signature to ensure the callback originates from our payment gateway and has not been tampered with.

> Note: You can find the API Secret [here](/dashboard/developers.md#api-secret).

#### Signature Generation

The signature is computed as follows:

* **Algorithm**: HMAC-SHA256
* **Input**: JSON stringified request body
* **Key**: Client-specific apiSecret
* **Output**: Hexadecimal string

#### Callback Request Format

* **Method**: POST (default, configurable)
* **Headers**:
  * Content-Type: application/json
  * Signature: \<hmac-sha256-signature>
* **Body**: JSON payload containing payment event details
* **Timeout**: 5000ms (default, configurable)

### <mark style="color:blue;">Verification Examples</mark>

Below are sample implementations to verify the signature in various programming languages.

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

```javascript
return akashicPay.verifySignature(
  body, signature
);
```

{% endtab %}

{% tab title="PHP" %}

```php
return $akashicPay->verifySignature(
  $body, $signature
);
```

{% endtab %}

{% tab title="Java" %}

```java
// with apiSecret
String apiSecret = "your apiSecret";
IAPSdk akashicPay = APSdkFactory.createSDK(APEnvironment.Development, otk, apiSecret);

String requestBody = "request body";
String headerSignature = "signature from requestHeader('key: Signature')";

boolean isVerify = akashicPay.verifySignature(
  requestBody, headerSignature
);

```

{% endtab %}

{% tab title="C#" %}

```csharp
// with apiSecret
string apiSecret = "your apiSecret";
IApSdk akashicPay = APSdkFactory.createSDK(APEnvironment.Development, otk, apiSecret);

string signature = response.Headers.GetValues("Signature").FirstOrDefault();
string responseBody = await response.Content.ReadAsStringAsync();

return akashicPay.VerifySignature(responseBody, signature);
```

{% endtab %}

{% tab title="Go" %}

```go
ap, err := akashicpay.NewAkashicPay(apKey, apL2Address, "Development", "ApiSecretGoesHere")

if err != nil {
    // Handle error
}

// Returns true if valid, indicating the callback has not been altered
verified, err := ap.VerifySignature(body, signature)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require 'openssl'
require 'json'
require 'date'

class SignatureVerifier
  def initialize(api_secret)
    @api_secret = api_secret
  end

  def verify_signature(body, signature)
    raise 'API secret not set' if @api_secret.nil?

    begin
      sorted_body = sort_keys(body)
      serialized = JSON.generate(sorted_body, quirks_mode: true, ascii_only: true)
      normalized_signature = signature.strip.gsub(/\A\*?"|"\*?\z/, '')
      computed = OpenSSL::HMAC.hexdigest('SHA256', @api_secret, serialized)
      computed == normalized_signature
    rescue => e
      puts "Verification error: #{e.message}"
      false
    end
  end

  private

  def sort_keys(obj)
    case obj
    when Array
      obj.map { |item| sort_keys(item) }
    when Hash
      obj.keys.sort.each_with_object({}) do |key, result|
        result[key] = sort_keys(obj[key])
      end
    when Time, Date, DateTime
      # Preserve as-is (like JS Date object passed to JSON.stringify)
      obj
    else
      obj
    end
  end
end
```

{% endtab %}
{% endtabs %}

### <mark style="color:blue;">Best Practices</mark>

* Store the apiSecret securely (e.g., in environment variables).
* Use secure comparison functions (like hash\_equals in PHP) to prevent timing attacks.
* Reject requests with missing or invalid signatures with a 401 Unauthorized response.

***

## <mark style="color:blue;">2. IP Whitelist</mark>

### <mark style="color:blue;">Overview</mark>

To restrict callback requests to trusted sources, we provide a fixed set of IP addresses from which callbacks will originate. Clients can whitelist these IPs in their firewall or application logic. Please contact AkashicPay support for a list of IPs to whitelist at [AkashicPay Support](https://t.me/akashicpay_support_bot).

### <mark style="color:blue;">Best Practices</mark>

* Configure your environment to use the appropriate IP list (Testnet or Mainnet).
* Regularly check for updates to the IP list in our documentation.
* Log and monitor requests from non-whitelisted IPs for security auditing.

***

## <mark style="color:blue;">3. Transaction Verification via API</mark>

### <mark style="color:blue;">Overview</mark>

Clients can independently verify payment events by querying our Transaction Detail API using either an L1 or L2 transaction hash. This method confirms the validity of the payment event referenced in the callback.

#### API Endpoints

**Base Domains**

* **Production**: <https://api.akashicscan.com>
* **Testnet**: <https://api.testnet.akashicscan.com>

**Endpoints**

* **L2 Hash Verification**:\
  GET /api/v0/transactions/transfer?l2Hash=\<L2\_HASH>\
  Example: <https://api.akashicscan.com/api/v0/transactions/transfer?l2Hash=AS123>..
* **L1 Hash Verification**:\
  GET /api/v0/transactions/hash?txHash=\<L1\_HASH>\
  Example: <https://api.akashicscan.com/api/v0/transactions/hash?txHash=0x123>..

#### Response Format

* **Status**: 200 OK on success
* **Body**: JSON object with transaction details (structure depends on implementation)
* **Error**: 4xx/5xx status codes with error message on failure

### <mark style="color:blue;">Best Practices</mark>

* Use the appropriate domain based on your environment (Testnet or Production).
* Implement retry logic for transient network failures.
* Cache successful verifications to reduce API calls, if applicable.

***

## <mark style="color:blue;">Security Considerations</mark>

* Use HTTPS for all callback endpoints to encrypt data in transit.
* Implement rate limiting to prevent abuse.
* Log all verification failures for monitoring and auditing.
* Keep your apiSecret and other sensitive credentials secure.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.akashicpay.com/callbacks/secure-callback-endpoint.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
