# Full Example

{% tabs %}
{% tab title="NodeJS: SubtleCrypto" %}

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

/* Message Signing Helpers */

/**
 * Convert a string to an array buffer
 * @param {string} str
 * @returns {string}
 */
function str2ab(str) {
    const buf = new ArrayBuffer(str.length);
    const bufView = new Uint8Array(buf);
    for (let i = 0, strLen = str.length; i < strLen; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

/**
 * Convert a string to base64-url safe encoding
 * @param {string} str
 * @returns {string}
 */
function base64UrlEncode(str) {
    return Buffer.from(str).toString('base64')
        .replace(/\+/g, '-')
        .replace(/\//g, '_')
        .replace(/=+$/, '');
}

/**
 * Import a private key and return a CryptoKey
 * @param {string} privateKeyDer base64 encoded private key der
 * @returns {Promise<CryptoKey>}
 */
async function getPrivateKeyFromDer(privKeyDer) {
    const decoded = Buffer.from(privKeyDer, 'base64').toString('binary');
    const buf = str2ab(decoded);
    return crypto.subtle.importKey('pkcs8', buf, {
        name: 'ECDSA',
        namedCurve: 'P-256',
    }, true, ['sign']);
}

/**
 * Sign a message with a private CryptoKey
 * @param {CryptoKey} privateKey
 * @param {string} message The message to sign
 * @returns {string} The signed message
 */
async function signMessage(privateKey, message) {
    return crypto.subtle.sign(
        {
            name: 'ECDSA',
            hash: 'SHA-256'
        }, 
        privateKey, 
        new TextEncoder().encode(message)
    );
}

/**
 * Create a request signature
 * @param {CryptoKey} privateKey
 * @param {string} date HTTP header date value
 * @param {string} method HTTP method value
 * @param {string} path HTTP path 
 * @param {string} [queryString] HTTP path query string (? not included)
 */
async function createRequestSignature({
    privateKey,
    date, 
    method, 
    path, 
    queryString = undefined
}) {
    const nonce = Date.now().toString();
    const sigParts = [
        method.toUpperCase(),
        path,
        queryString,
        date,
        nonce
    ].filter(str => str && str.length !== 0);
    const signature = await signMessage(privateKey, sigParts.join('\n'));
    return base64UrlEncode(signature) + '.' + base64UrlEncode(nonce);
}

/* HTTP Request */

const API_URL = 'https://int.quadrata.com';
const API_KEY = '...';

/**
 * Send a signed request
 * @param {CryptoKey} privateKey
 * @param {string} method HTTP method value
 * @param {string} path HTTP path
 * @param {string} [queryString] HTTP path query string (? not included)
 * @param {object} [body] HTTP body payload
 * @param {object} [extraHeaders] Optional headers to send with the request
 * @returns {Promise<Response|void>}
 */
async function makeRequest({
    privateKey, 
    method, 
    path, 
    queryString = undefined,
    body = undefined,
    extraHeaders = undefined
}) {
    const date = (new Date()).toUTCString();
    const signature = await createRequestSignature({
        privateKey,
        method,
        path,
        queryString,
        date
    });
    const headers = {
        ...extraHeaders,
        'Authorization': `Basic ${Buffer.from(API_KEY).toString('base64')}`,
        'Date': date,
        'Signature': signature
    };
    let urlPath = `${API_URL}${path}`;
    if (queryString && queryString.length !== 0) {
        urlPath += `?${queryString}`;
    }
    const response = await fetch(urlPath, {
        method,
        headers,
        body: body ? JSON.stringify(body) : undefined
    });
    if (!response.ok) {
        console.error(response);
        return;
    }
    return response.json();
}

/**
 * Base64 Encoded Private Key DER
 * @type {string}
 */
const privateKeyDer = '...';

/**
 * @type {CryptoKey}
 */
const privateKey = await getPrivateKeyFromDer(privateKeyDer);

/**
 * @type {string}
 */
const walletAddress = '...';

// make the request
const json = await makeRequest({
    method: 'GET',
    privateKey: privateKey,
    path: `/api/v1/wallets/${encodeURIComponent(walletAddress)}/screening`,
});


```

{% endtab %}

{% tab title="Python" %}

```python
import base64
import requests

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey, ECDSA
from cryptography.hazmat.primitives import hashes
from datetime import datetime, timezone
from secrets import token_hex
from typing import Any, Dict, Optional, Union

API_URL = 'http://int.quadrata.com'
API_KEY = b'...'
PRIVATE_KEY_DER = b'...'  # base64 encoded private key der

def b64_url_encode(bstr: bytes) -> str:
    return base64.urlsafe_b64encode(bstr).rstrip(b'=').decode('utf-8')

def private_key_from_der(
    der: bytes, 
    password: Optional[bytes] = None
) -> EllipticCurvePrivateKey:
    return serialization.load_der_private_key(base64.b64decode(der), password)

def create_sig(
    priv_key: EllipticCurvePrivateKey,
    method: str,
    path: str,
    date: str,
    query_string: Optional[str] = None
) -> str:
    nonce = token_hex(10)
    return b64_url_encode(        
        priv_key.sign(
            '\n'.join(
                list(
                    filter(
                        lambda s: s and len(s) > 0,
                        [
                            method.upper(),
                            path,
                            query_string if query_string else None,
                            date,
                            nonce,
                        ],
                    )
                )
            ).encode('utf-8'),
            ECDSA(hashes.SHA256()),
        )
    ) + (f'.{b64_url_encode(bytes(nonce, "utf-8"))}')

def make_request(
    path: str,
    method: str = 'get',
    query_string: Optional[str] = None,
    extra_headers: Optional[Dict[str, Any]] = None
) -> str:
    request_action = getattr(requests, method.lower(), None)
    if request_action is None:
        raise ValueError(f'Invalid method provided: {method}')
    date = datetime.now(timezone.utc).strftime('%a, %d %b %Y %H:%M:%S GMT')
    sig = create_sig(
        priv_key=private_key_from_der(PRIVATE_KEY_DER),
        method=method,
        path=path,
        date=date,
        query_string=query_string
    )
    url_path = f'{API_URL}{path}'
    if query_string is not None and len(query_string) != 0:
        url_path += f'?{query_string}'
    response = request_action(
        url_path,
        headers={
            'Authorization': f'Basic {base64.b64encode(API_KEY).decode()}',
            'Signature': sig,
            'Date': date
        } | (extra_headers if extra_headers is not None else {})
    )
    return response.json()

wallet_address = '...'

api_response = make_request(f'/api/v1/wallets/{wallet_address}/screening')

```

{% 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.quadrata.com/integration/how-to-integrate/on-chain-wallet-screening/how-to-sign-api/full-example.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.
