# Encryption

The encryption method we use follows the steps outlined below.

{% tabs %}
{% tab title="JavaScript" %}
{% code overflow="wrap" fullWidth="false" %}

```javascript
private flattenObject(obj, prefix = '',) {
  let result = {};
  
  for (const key of Object.keys(obj)) {
    const value = obj[key];
    const fullKey = prefix ? `${prefix}.${key}` : key;

    if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
      result = { ...result, ...this.flattenObject(value, fullKey) };
    } else {
      result[fullKey] = value;
    }
  }

  return result;
}
  
private buildKeyValueString(obj) {
  // Flatten all keys (including nested like extendParams.foo, extendParams.bar)
  const flat = this.flattenObject(obj);
  const sortedKeys = Object.keys(flat).sort();

  const keyValuePairs = sortedKeys.map((key) => {
    const value = flat[key];
    return `${key}=${value}`;
  });

  return keyValuePairs.join('&');
}

generateSignature(secret, body) {
  const keyString = `${partnerId}:${this.buildKeyValueString(body)}`;

  // Include the generated signature in the x-signature header.
  const signature = createHmac('sha256', secret)
    .update(keyString)
    .digest('hex');

  return signature;
}
```

{% endcode %}
{% endtab %}

{% tab title="PHP" %}

```php
<?php

class SignatureHelper
{
    private function flattenObject(array $obj, string $prefix = ''): array
    {
        $result = [];

        foreach ($obj as $key => $value) {
            $fullKey = $prefix !== '' ? $prefix . '.' . $key : $key;

            if (is_array($value) && array_values($value) !== $value) {
                $result = array_merge($result, $this->flattenObject($value, $fullKey));
            } else {
                $result[$fullKey] = $value;
            }
        }

        return $result;
    }

    private function buildKeyValueString(array $obj): string
    {
        $flat = $this->flattenObject($obj);
        ksort($flat); // sort keys alphabetically

        $keyValuePairs = [];
        foreach ($flat as $key => $value) {
            // handle boolean to string
            if (is_bool($value)) {
                $value = $value ? 'true' : 'false';
            }

            $keyValuePairs[] = "{$key}={$value}";
        }

        return implode('&', $keyValuePairs);
    }

    public function generateSignature(string $partnerId, string $secret, array $body): string
    {
        $keyString = $partnerId . ':' . $this->buildKeyValueString($body);
        // Include the generated signature in the x-signature header.
        return hash_hmac('sha256', $keyString, $secret);
    }
}

```

{% endtab %}

{% tab title="Golang" %}

```go
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"sort"
	"strconv"
)

func flattenObject(data map[string]interface{}, prefix string) map[string]string {
	result := make(map[string]string)

	for k, v := range data {
		fullKey := k
		if prefix != "" {
			fullKey = prefix + "." + k
		}

		switch value := v.(type) {
		case map[string]interface{}:
			flattened := flattenObject(value, fullKey)
			for fk, fv := range flattened {
				result[fk] = fv
			}
		case bool:
			if value {
				result[fullKey] = "true"
			} else {
				result[fullKey] = "false"
			}
		case float64:
			result[fullKey] = strconv.FormatFloat(value, 'f', -1, 64)
		default:
			result[fullKey] = fmt.Sprintf("%v", value)
		}
	}

	return result
}

func buildKeyValueString(obj map[string]interface{}) string {
	flat := flattenObject(obj, "")
	keys := make([]string, 0, len(flat))
	for k := range flat {
		keys = append(keys, k)
	}
	sort.Strings(keys)

	pairs := make([]string, 0, len(keys))
	for _, k := range keys {
		pairs = append(pairs, fmt.Sprintf("%s=%s", k, flat[k]))
	}

	return fmt.Sprintf("%s", joinWithAmpersand(pairs))
}

func joinWithAmpersand(parts []string) string {
	result := ""
	for i, part := range parts {
		if i > 0 {
			result += "&"
		}
		result += part
	}
	return result
}

func generateSignature(partnerId, secret string, body map[string]interface{}) string {
	keyString := partnerId + ":" + buildKeyValueString(body)
	fmt.Println("🔍 keyString:", keyString)

	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(keyString))
	// Include the generated signature in the x-signature header.
	return hex.EncodeToString(h.Sum(nil))
}

```

{% endtab %}
{% endtabs %}


---

# 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.whalepay.one/encryption.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.
