# API 接口加签

本文是[FaTPay API 加签](/zh/reference/api-reference/verification.md#api-qing-qiu-jie-kou-jia-qian) 的 demo

{% hint style="info" %}
使用本文代码时，请务必将其中的合作伙伴账号相关信息替换为您自身的
{% endhint %}

{% tabs %}
{% tab title="Java" %}
{% code lineNumbers="true" %}

```java
package onramp.apisign;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

/**
 * SignUtil
 *
 * @author FaTPay
 */
public class SignUtil {

    private static final Logger LOG = LoggerFactory.getLogger(SignUtil.class);

    /**
     * Signature algorithms
     */
    public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    private static final String RSA_ALGORITHM = "RSA";

    /**
     * RSA private key
     */
    private static final String PRIVATE_KEY = "<YOUR RSA PRIVATE KEY>";

    /**
     * partnerId
     */
    private static final String PARTNERID = "<YOUR PARTNER ID>";

    /**
     * FaTPay domain
     */
    private static final String DOMAIN = "https://api.ramp.fatpay.xyz";

    /**
     * apis
     */
    private static final String ONRAMP_TOKEN = "/open/api/onramp/token";
    private static final String ONRAMP_CURRENCY = "/open/api/onramp/currency";
    private static final String ONRAMP_PRICE = "/open/api/onramp/price";
    private static final String ONRAMP_ORDER = "/open/api/onramp/order";

    /**
     * Generates the signature
     *
     * @param params
     * @param rsaPrivate
     * @return
     */
    public static String rsaSign(Map<String, String> params, String rsaPrivate, String presign) {
        try {
            rsaPrivate = StringUtils.replace(rsaPrivate, "-----BEGIN PRIVATE KEY-----", "");
            rsaPrivate = StringUtils.replace(rsaPrivate, "-----END PRIVATE KEY-----", "");
            String sign = doSign(presign + paramsToStr(params), rsaPrivate);
            return sign;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * Generates the signature
     *
     * @param content    Content to be signed
     * @param privateKey private key
     * @return
     */
    public static String doSign(String content, String privateKey) {
        try {
            byte[] decoded = Base64.decodeBase64(privateKey);
            PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(decoded);
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8);

            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initSign(priKey);
            signature.update(content.getBytes(StandardCharsets.UTF_8));
            byte[] signed = signature.sign();
            return Base64.encodeBase64String(signed);
        } catch (Exception ex) {
            LOG.error("RSA sign failed，content={}", content, ex);
            throw new IllegalArgumentException("RSA sign failed");
        }
    }

    /**
     * Converts parameters into ordered strings
     *
     * @param params
     * @return
     */
    private static String paramsToStr(Map<String, String> params) {
        StringBuilder param = new StringBuilder();
        List<String> keys = new ArrayList(params.keySet());
        // Sorts the specified keys
        Collections.sort(keys);
        int index = 0;
        Iterator<String> iterator = keys.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = params.get(key);
            // Filter out null and empty values
            if ("x-fp-signature".equals(key) || "signature".equals(key) || "sign".equals(key) || StringUtils.isBlank(value)) {
                continue;
            }
            param.append(index == 0 ? "" : "&").append(key).append("=").append(value);
            index++;
        }
        return param.toString();
    }
    
    /**
     * Returns URI
     *
     * @param url
     * @return
     */
    public static URI getURI(String url) {
        if (!(StringUtils.startsWithIgnoreCase(url, "http://") || StringUtils
                .startsWithIgnoreCase(url, "https://"))) {
            url = "http://" + url;
        }
        try {
            URI uri = new URI(url);
            return uri;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // ******************** OPEN API DEMO START ********************//
    public static void openApiDemo() {
        // header
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("X-FP-Version", "v1.0");
        headerMap.put("X-FP-Timestamp", "1661338357");
        headerMap.put("X-FP-Nonce", "868964");
        headerMap.put("X-FP-Partner-Id", PARTNERID);

        // parameters
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("fiatCurrency", "USD");
        paramMap.put("currencyAmount", "199");
        paramMap.put("cryptoCurrencyCode", "USDT_ERC20");
        paramMap.put("payment", "BANK_CARD_TRANSFER");

        // Converts keys to lower case
        Map<String, String> headerMapLowerCase = new HashMap<>();
        Set<String> strings = headerMap.keySet();
        strings.forEach(s -> {
            headerMapLowerCase.put(s.toLowerCase(), headerMap.get(s));
        });

        // Parameters to be signed
        Map<String, String> params = new HashMap<>();
        params.putAll(headerMapLowerCase);
        params.putAll(paramMap);

        // example
        String url = DOMAIN.concat(ONRAMP_PRICE);
        URI uri = getURI(url);

        // prefix
        String presign = "GET" + uri.getHost() + uri.getPath() + "?";
        String sign = "";
        try {
            // Generates the signature
            sign = SignUtil.rsaSign(params, PRIVATE_KEY, presign);
        } catch (Exception e) {
            LOG.error("rsaSign error, exception:{}", e);
        }
        headerMap.put("X-FP-Signature", sign);
        // TODO Send http request with above parameters (url, paramMap, headerMap)
        LOG.info("url:{}, paramMap:{}, headerMap:{}", url, paramMap, headerMap);
    }
    // ******************** OPEN API DEMO END ********************//

}


```

{% endcode %}
{% endtab %}

{% tab title="Node.js" %}
{% code lineNumbers="true" %}

```jsx
const crypto = require('crypto');

var text = "original text to be signed"
var privatekey = "private key to generate sign"

// generate signature
var signerObject = crypto.createSign("RSA-SHA256");
signerObject.update(text);
var signature = signerObject.sign(privatekey, "base64");
console.info("signature: " + signature);
```

{% endcode %}
{% 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://dev.fatpay.org/zh/appendix/demo/api-signature-demo.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.
