Guides
NEXUS

End point APIs


APIs

프로젝트 설정에 필요한 End point API 에 대한 설명 입니다.

접속 링크

Webview(모바일), 시스템 브라우저(데스크탑) 환경에서 RAMP F/E 로드하기 위한 URL에 대한 설명 입니다.
프로젝트 생성시 projectID 를 포함한 램프 접근 URL이 생성 됩니다.

https://ramp.crosstoken.io/catalog?projectId={{projectID}}&sessionId={{sessionId}}&accessToken={{accessToken}}&platform=web&network=testnet


파라미터 설명

파라미터명

설명

필수여부

projectId

넥써쓰에서 발급하는 Project ID

필수

sessionId

유저의 게임 캐릭터 식별 ID

필수

accessToken

인게임 유저 인증 토큰 RAMP B/E 에서 개발사 서버로 게임 재화 조회 요청시 사용됩니다.

필수

network

Mainnet, Testnet 구분

필수

lang

언어 선택 (zh, en, zh-Hant)

선택

platform

web

선택


유저의 게임 재화 조회 API

토큰 발행을 위해 유저가 보유한 게임 재화를 조회하는 API 구현이 필요 합니다. 조회된 게임 재화는 RAMP F/E 페이지에 표현됩니다.

RAMP B/E에서 게임 재화 조회 API를 호출할 때는, 게임 내에서 토큰 발행 또는 소각을 위해 로드되는 RAMP F/E URL의 쿼리 파라미터에 포함된 accessToken 및 sessionId 값을 Request Header에 함께 포함하여 전송합니다.
따라서 개발사 서버에서는 해당 accessToken을 검증하고, 검증 결과에 따른 적절한 응답(Response) 을 반환해야 합니다.

CROSS-RAMP Console 프로젝트에 설정한 Get Assets End point 로 요청을 하게 됩니다.


Request / Response

RAMP B/E 에서 개발사가 구현한 End

Request 샘플

GET /api/assets
Host: https://your-server.com
Content-Type: application/json
X-Dapp-Authorization: Bearer {{accessToken}}
X-Dapp-SessionID: {{sessionId}}

Request Header 필드 설명

필드명

설명

X-Dapp-Authorization

개발사 서버에서 생성한 accessToken 입니다. RAMP F/E 로드시 Query 에 추가한 accessToken 값을 사용합니다.

X-Dapp-SessionID

개발사에서 관리하는 유저의 캐릭터 식별 ID 입니다. RAMP F/E 로드시 Query 에 추가한 sessionId 값을 사용합니다.


Response 샘플

성공 응답 (200 OK)

{
  "success": true,
  "errorCode": null,
  "data": {
    "v1": {
      "player_id": "player_id_allen",
      "name": "name_allen",
      "wallet_address": "0x62c5a30a90d3c3032dfb0fe4ea05e9c454c56707",
      "server": "test",
      "assets": [
        {
          "id": "item_gold",
          "balance": "1000.123"
        }
      ]
    }
  }
}

Response 필드 설명

필드명

타입

설명

success

boolean

요청 성공 여부

errorCode

string

오류 코드 (성공시 null)

data

object

응답 데이터 (실패시 null)

data.v1

object

API 버전 1 데이터

data.v1.player_id

string

유저 캐릭터 고유 ID

data.v1.name

string

유저 캐릭터 이름

data.v1.wallet_address

string

유저 지갑 주소

data.v1.server

string

유저 캐릭터 접속 서버 정보

data.v1.assets

array

유저의 게임 재화 보유 목록

data.v1.assets[].id

string

게임 재화 고유 식별자
RAMP 콘솔에서 설정된 게임 재화 ID가 입력되어야 합니다.

data.v1.assets[].balance

string

유저의 게임 재화 보유 수량
게임내 유저의 재화 보유 수량이 입력되어야 합니다.




유저의 서명 검증 조회 API

토큰 발행 과정에서, 유저의 서명(Signature) 값과 개발사에서 전송한 트랜잭션 요청 데이터가 일치하는지 검증하는 API 구현이 필요합니다.

데이터 무결성 검증을 위해 CROSS-RAMP Console 에서 생성된 HMAC-SHA256 으로 서명한 데이터를 Request Header 에 포함하여 요청을 합니다.
따라서 개발사 서버에서는 CROSS-RAMP Console 의 HMAC 값을 이용하여 무결성 검증을 해야 합니다.


유저의 토큰 발행 / 소각 요청이 개발사 정책에 위배 되는지 검증 후(인증, 게임 재화 수량 등), 응답이 필요 합니다.

CROSS-RAMP Console 프로젝트에 설정한 Validate Order End point 로 요청을 하게 됩니다.


Request / Response

Request 샘플

POST /api/validate
Host: https://your-server.com
Content-Type: application/json
x-dapp-authorization: Bearer {{accessToken}}
x-dapp-sessionid: {{sessionId}}
x-hmac-signature: {{hmac_signature}}

{
  "user_sig": "0x58ea88cc20a571d2bc4f4a7ab687158e1924887c005a8a2ccce9a7c8f669adbb222932f9e760b923b6f359870169d58a171d47516ee71167313d5068dbd84c631c",
  "user_address": "0x6de346a7333d97fe0d39a49178ac65918c257b28",
  "project_id": "3a4----------------------2d7",
  "digest": "0x6d196d0881bb8e322c194fbf53518089b240055134044491a78b14920098e395",
  "uuid": "86b555dd-e622-43fe-a799-c5c4536dd8c6",
  "intent": {
    "method": "mint",
    "type": "assemble",
    "from": [
      {
        "type": "asset",
        "id": "item_gold",
        "amount": 100
      }
    ],
    "to": [
      {
        "type": "ERC20",
        "id": "0x14f6f0057274c3519d6258EB66F5d01D79821D81",
        "amount": 1
      }
    ],
    "target_candidate": {}
  }
}
POST /api/validate
Host: https://your-server.com
Content-Type: application/json
x-dapp-authorization: Bearer {{accessToken}}
x-dapp-sessionid: {{sessionId}}
x-hmac-signature: {{hmac_signature}}

{
  "user_sig": "0xb1378a978b5e77d750c44d4b9bdf4d883d2e2bad8e09c8928e8d83176359cc9376a959c3576c82f2214c9fece66c73417669bf667734ec8f94880885c5d1b82a1c",
  "user_address": "0x6de346a7333d97fe0d39a49178ac65918c257b28",
  "project_id": "3a4f5838f7cdfe31873a43ca021a92d7",
  "digest": "0x7bd721630a8c7e6b1c1050934fc3bf69cadaef0253c46f92f1b03242c5f2e733",
  "uuid": "d7360515-8547-427e-acb5-6556c8376fd4",
  "intent": {
    "method": "burn-permit",
    "type": "disassemble",
    "from": [
      {
        "type": "ERC20",
        "id": "0x14f6f0057274c3519d6258EB66F5d01D79821D81",
        "amount": 1
      }
    ],
    "to": [
      {
        "type": "asset",
        "id": "item_gold",
        "amount": 50
      }
    ],
    "target_candidate": {}
  }
}

Request Header 필드 설명

필드명

설명

X-Dapp-Authorization

개발사 서버에서 생성한 accessToken 입니다. RAMP F/E 로드시 Query 에 추가한 accessToken 값을 사용합니다.

X-Dapp-SessionID

개발사에서 관리하는 유저의 캐릭터 식별 ID 입니다. RAMP F/E 로드시 Query 에 추가한 sessionId 값을 사용합니다.


Request Body 필드 설명

필드명

타입

설명

user_sig

string

유저의 토큰 발행 / 소각을 위해서 CROSSx 를 통해 서명한 데이터.

user_address

string

유저의 CROSSx 주소

project_id

string

RAMP 콘솔에서 생성한 프로젝트 ID

digest

string

트랜잭션 데이터의 해시 다이제스트 개발사에서 생성한 Validator 키를 이용해서 서명할 원문 입니다.

uuid

string

요청 고유 식별자

intent

object

토큰 발행 / 소각 정보

intent.method

string

실행 방법 (mint, burn)

intent.type

string

트랜잭션 타입 (assemble, disassemble)

  • assemble : 토큰 발행
  • disassemble : 토큰 소각

intent.from

array

소스 자산 정보 목록

intent.from[].type

string

자산 타입 (asset큰, ERC20)

  • asset : 게임 자산
  • ERC20 : 게임 토

intent.from[].id

string

CROSS-RAMP Console 에 등록한 게임 재화 ID.

intent.from[].amount

number

토큰 발행에 사용된 게임 재화 수량

intent.to

array

대상 자산 정보 목록

intent.to[].type

string

자산 타입 (ERC20, NFT)

intent.to[].id

string

토큰 컨트랙트 주소

intent.to[].amount

number

발행할 토큰 수량

intent.target_candidate

object

대상 후보 정보 (추가 옵션)


Response 샘플

성공 응답 (200 OK)

{
  "success": true,
  "errorCode": null,
  "data": {
    "userSig": "0x58ea88cc20a571d2bc4f4a7ab687158e1924887c005a8a2ccce9a7c8f669adbb222932f9e760b923b6f359870169d58a171d47516ee71167313d5068dbd84c631c",
    "validatorSig": "0xfd7c12023378170c615bdd63be3e7aa195ff98b42fe84dad34348017fc1050db157e077dd5053328040b476479edebfe5d773bb8602de6bc088951de7b597fd31b"
  }
}

Response 필드 설명

필드명

타입

설명

success

boolean

요청 성공 여부

errorCode

string

오류 코드 (성공시 null)

data

object

응답 데이터 (실패시 null)

data.userSig

string

토큰 발행 / 소각을 위해 유저가 CROSSx 를 통해서 서명한 데이터 입니다.

data.validatorSig

string

개발사에서 생성한 Validator 키를 이용해서 ECDSA 서명한 데이터 입니다.
Validator 키의 주소는 CROSS-RAMP Console 에 등록이 되어 있어야 합니다.



유저의 토큰 발행 / 소각 결과 API

유저의 토큰 발행 / 소각 요청에 대한 블록체인상 트랜잭션 결과를 게임 서버로 Webhook 으로 전달 합니다.

CROSS-RAMP Console 에 등록된 End point 로 트랜잭션 결과를 전달하며, 개발사 서버에서는 결과 수신 후 Http 상태 값을 200 으로 응답 해야 합니다.


RAMP B/E 에서 응답을 받지 못하거나 HTTP 500 코드를 수신하는 경우 RAMP B/E 에서 재전송을 하게됩니다.
정상적인 처리를 위해서 HTTP 200 코드를 응답해야 합니다.

📘

재시도 정보

Webhook 전달 첫번째 시도 후 12시간 동안 최대 20회까지 재전송을 시도 합니다.

  • 5분 간격 2회 시도
  • 15분 간격으로 7번 시도
  • 60분 간격으로 10번 시도

Webhook request / response

receipt.status 가 0x1 이 아닌 경우에는 블록체인 네트워크상 트랜잭션 요청 실패 이므로 게임 재화를 복구해야 합니다.

Request 샘플

POST /api/result
Host: https://your-server.com
Content-Type: application/json
x-dapp-authorization: Bearer {{accessToken}}
x-dapp-sessionid: {{sessionId}}
x-hmac-signature: {{hmac_signature}}

{
    "session_id": "{{dappSessionId}}",
    "uuid": "b6d3976b-36b1-48d6-974b-da1471aa94de",
    "tx_hash": "0x17def972330f874dcfbc8099ada5da777c4273e3c0aa6faebb103e09615f5784",
    "receipt": {
        "type": "0x2",
        "root": "0x",
        "status": "0x1",
        "cumulativeGasUsed": "0x1f531",
        "logsBloom": "0x00000000080040000000200a00000000000000000000000000000000000000000000010000000000002000100000000000000000000000000000000000000000000000100820000400000008000000000000000000000000000000000000110000040000020000000000000000000800000040000000000000000010000000000000000008000000000000080000000000000000000000000000000000100000000000000000000000000400000002000000000000000000000000000000000000000002000000000000000000020800000002000000000000000000000020400000000000000000000200000000000000000000000000000800000000000000",
        "logs": [
            {
                "address": "0x14f6f0057274c3519d6258eb66f5d01d79821d81",
                "topics": [
                    "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
                    "0x0000000000000000000000000000000000000000000000000000000000000000",
                    "0x0000000000000000000000006de346a7333d97fe0d39a49178ac65918c257b28"
                ],
                "data": "0x0000000000000000000000000000000000000000000000003e73362871420000",
                "blockNumber": "0xaa3d8f",
                "transactionHash": "0x17def972330f874dcfbc8099ada5da777c4273e3c0aa6faebb103e09615f5784",
                "transactionIndex": "0x0",
                "blockHash": "0x5b62d0387e2f37ea7c76cde2b08b1a36648aca277c76152fdf0da59e6ee63733",
                "blockTimestamp": 0,
                "logIndex": "0x0",
                "removed": false
            },
            {
                "address": "0x7189d67b9ded72e9f1dcfce1c23ea3af418f4a57",
                "topics": [
                    "0x9612604afba70e4cf03261d7d86ca03d08911d9887aa41621dea929e34cfd7b1",
                    "0x3361346635383338663763646665333138373361343363613032316139326437",
                    "0x171ac396aacce04a8c32ecd6322f384796a2a5e15224316a78c9358a8cea809b",
                    "0x0000000000000000000000006de346a7333d97fe0d39a49178ac65918c257b28"
                ],
                "data": "0x00000000000000000000000014f6f0057274c3519d6258eb66f5d01d79821d810000000000000000000000000000000000000000000000004563918244f40000",
                "blockNumber": "0xaa3d8f",
                "transactionHash": "0x17def972330f874dcfbc8099ada5da777c4273e3c0aa6faebb103e09615f5784",
                "transactionIndex": "0x0",
                "blockHash": "0x5b62d0387e2f37ea7c76cde2b08b1a36648aca277c76152fdf0da59e6ee63733",
                "blockTimestamp": 0,
                "logIndex": "0x2",
                "removed": false
            }
        ],
        "transactionHash": "0x17def972330f874dcfbc8099ada5da777c4273e3c0aa6faebb103e09615f5784",
        "contractAddress": "0x0000000000000000000000000000000000000000",
        "gasUsed": "0x1f531",
        "effectiveGasPrice": "0xee6b2800",
        "blockHash": "0x5b62d0387e2f37ea7c76cde2b08b1a36648aca277c76152fdf0da59e6ee63733",
        "blockNumber": "0xaa3d8f",
        "transactionIndex": "0x0"
    },
    "intent": {
        "method": "mint",
        "type": "assemble",
        "from": [
            {
                "type": "asset",
                "id": "item_gold_n",
                "amount": 500
            }
        ],
        "to": [
            {
                "type": "ERC20",
                "id": "0x14f6f0057274c3519d6258EB66F5d01D79821D81",
                "amount": 5
            }
        ],
        "target_candidate": {}
    }
}

response 샘플

POST /api/result
Host: https://your-server.com
Content-Type: application/json

{
  "success": true,
  "errorCode": null,
  "data": null
}

HMAC 서명 및 Validator 서명 샘플

HMAC 서명 샘플

const crypto = require('crypto');

function generateHmacSignature(payload, secretKey) {
  // JSON 데이터를 문자열로 변환
  const dataString = JSON.stringify(payload);
  
  // HMAC-SHA256으로 서명 생성
  const hmac = crypto.createHmac('sha256', secretKey);
  hmac.update(dataString);
  const signature = hmac.digest('hex');
  
  return signature;
}

// 서명 검증 함수
function verifyHmacSignature(payload, receivedSignature, secretKey) {
  const expectedSignature = generateHmacSignature(payload, secretKey);
  
  // 타이밍 공격 방지를 위한 안전한 비교
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature, 'hex'),
    Buffer.from(receivedSignature, 'hex')
  );
}

// 사용 예시
const secretKey = 'your_secret_key_from_console';
const requestData = {
  sessionId: 'player_12345',
  assetId: 'gold_coin',
  amount: '100.50'
};

// 서명 생성
const signature = generateHmacSignature(requestData, secretKey);
console.log('Generated signature:', signature);

// 서명 검증
const isValid = verifyHmacSignature(requestData, signature, secretKey);
console.log('Signature valid:', isValid);

Validator 서명 샘플

import { ethers } from "ethers";

/**
 * generateValidatorSignature
 * 
 * Signs the given digest using the validator's private key.
 * The digest must be a 32-byte hash (e.g. "0xabc123...").
 * 
 * @param {string} userSig - (optional) user's signature
 * @param {string} digest  - 32-byte digest to sign
 * @returns {Promise<{ success: boolean, signature?: string, error?: string }>}
 */
export async function generateValidatorSignature(userSig, digest) {
  try {
    // Load validator private key (from env or default)
    const privateKey =
      process.env.VALIDATOR_PRIVATE_KEY;

    // Create an Ethers.js Wallet instance
    const wallet = new ethers.Wallet(privateKey);

    // Convert digest (hex) to byte array
    const digestBytes = ethers.getBytes(digest);

    // Sign the digest (must be 32 bytes)
    const rawSignature = await wallet.signingKey.sign(digestBytes);

    // Serialize signature (r + s + v)
    const signature = ethers.Signature.from(rawSignature).serialized;

    // Return success response
    return {
      success: true,
      signature,
    };
  } catch (error) {
    console.error("Error generating validator signature:", error);

    // Return failure response
    return {
      success: false,
      error: error.message,
    };
  }
}

© 2025 NEXUS Co., Ltd. All Rights Reserved.