> For the complete documentation index, see [llms.txt](https://docs.quadrata.com/passport-issuer/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.quadrata.com/passport-issuer/integration-developers/attesting-attributes/1.-api-request.md).

# 1. API Request

Quadrata is providing an [npm package](https://github.com/QuadrataNetwork/quadrata-npm) for all DApps supporting Quadrata Passport technology.\
The npm package is responsible for collecting user information and sending those information to the issuers directly via an API call.

\
The overall API payload structure will differ from issuers to issuers as the data collected varies.

It is the responsibility of a passport issuers to have an API that includes at least the following fields:

### Request Payload

```json
{
    'account': '',
    'sigAccount': '',
    'chainId': ''

    // Remaining Issuer specific Request Payload
}
```

<table><thead><tr><th width="232">Field</th><th>Description</th></tr></thead><tbody><tr><td>account</td><td>Wallet address of the user to verify </td></tr><tr><td>sigAccount</td><td>Ethereum ECDSA signature of a digest to prove ownership of the wallet account:</td></tr><tr><td>chainId</td><td>Blockchain Network Id. (ex: 1 for Ethereum Mainnet, 137 for Polygon). <br><br>See <a href="https://chainlist.org/">list of chain ID</a>.</td></tr></tbody></table>

#### **sigAccount**

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

```javascript
const { Signer, Wallet } = require("ethers");


export const signAccount = async (
  signer: typeof Signer
): Promise<typeof DataHexString> => {
  const DIGEST_TO_SIGN = "Welcome to Quadrata! By signing, you agree to the Terms of Service.";
  const sig = await signer.signMessage(DIGEST_TO_SIGN);
  return sig;
};

const signer = new Wallet(ACCOUNT_PRIVATE_KEY);

const account = signer.address;
const sigAccount = await signAccount(signer)
```

{% endtab %}

{% tab title="Python" %}

```python
import codecs
import eth_abi
from web3 import Web3  # type: ignore

W3_TIMEOUT = 60
NETWORK_URI = "" # INFURA_RPC_NODE
ACCOUNT_PRIVATE_KEY = "" # PRIVATE_KEY_USED_TO_SIGN] 

def generate_mint_signature() -> Optional[str]:
    decoder = codecs.getdecoder('hex_codec')
    digest = "Welcome to Quadrata! By signing, you agree to the Terms of Service."

    decoder = codecs.getdecoder('hex_codec')
    w3 = Web3(Web3.HTTPProvider(NETWORK_URI, request_kwargs={'timeout': W3_TIMEOUT}))

    return w3.eth.account.sign_message(
        encode_defunct(hexstr=digest),
        private_key=decoder(str.encode(ACCOUNT_PRIVATE_KEY))[0],
    ).signature.hex()
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
It is the responsibility of the issuers to verify that the `sigAccount` matches the `account.`
{% endhint %}

#### **Signature Verification**

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

```javascript
const { ethers } = require("ethers"); 

const verifyAccountSig = (account, sigAccount) => {
  const recoveredAddress = ethers.utils.recoverAddress(
    "Welcome to Quadrata! By signing, you agree to the Terms of Service.", 
    sigAccount
  );
  
  return recoveredAddress == account;
}
```

{% endtab %}

{% tab title="Python" %}

```python
import eth_abi
from web3.auto import w3  # type: ignore
from eth_account.messages import encode_defunct

W3_TIMEOUT = 60


def is_verified_signature(
    signature: str, 
    expected_wallet_address: str
) -> bool:
    digest = "Welcome to Quadrata! By signing, you agree to the Terms of Service."
    try:
        encoded_msg = encode_defunct(text=digest)
        recovered_address = w3.eth.account.recover_message(
            encoded_msg, 
            signature=signature
        )
    except Exception:  # Intentionally broad as the errors thrown are not documented well
        return False

    return expected_wallet_address.lower() == recovered_address.lower()
```

{% endtab %}
{% endtabs %}
