API Reference

Create #OneTap links to pay/buy/mint on-chain in 5min!

1️⃣ Mint Your Free Developer Card


2️⃣ Update Your Profile

Configure your identity to help users recognize you when you share your links with them:


3️⃣ Store API Keys Safely

Ensure your API keys are securely stored for easy access:


4️⃣ Create Intent Links

Create links to help your users directly transact on-chain in #OneTap:

🪙 Minting

Deploy & distribute tokens to users:

  1. Deploy Contract:
    • Use Deploy NFT or Deploy ERC-20 API.
    • Copy the orderId from the response.
    • Query the orderStatus using the Get Order endpoint.
    • Extract the address field from the deployedSmartContract section of the status response.
  2. Create Minting Link:

💰 Payments

Request on-chain payments from user wallets to your own:

  1. Create a payment link using the Create Payment Link API.
  2. Copy the link from the response and share it with your users.

📈 Trades

Help users buy tokens on-chain and earn affiliate fees:

  1. Create Buy Link: Generate a token referral link for user-specified purchase amounts.
  2. Create Buy Link with Amount: Create a link for buying a pre-fixed amount of tokens in USDC.
  3. Create Sell Link with Amount: Create a link for selling a pre-fixed amount of tokens for USDC.

5️⃣ Register Your Webhook

Stay updated with real-time notifications:

  • Register your webhook using Set WebHook to receive server updates whenever users fulfill intents.
  • Here's the structure of a webhook response:
{
  "Order": {
    "type": "object",
    "properties": {
      "id": {
        "type": "string",
        "format": "uuid",
        "description": "Unique identifier for the order.",
        "example": "ca7fc2a9-4e7f-4580-9caf-7026d4c0ca3e"
      },
      "status": {
        "type": "string",
        "description": "Current status of the order.",
        "enum": [
          "Initial",
          "ProcessingFiatProviderOrder",
          "PaymentReceivedOnFiatProvider",
          "BlockchainTransactionSubmission",
          "Completed",
          "Failed"
        ],
        "example": "Completed"
      },
      "createdAt": {
        "type": "string",
        "format": "date-time",
        "description": "Timestamp when the order was created.",
        "example": "2024-08-05T15:01:19.447Z"
      },
      "blockchainTransactionHash": {
        "type": "string",
        "description": "Hash of the blockchain transaction associated with the order.",
        "example": "0x11e60b014f3d9544b4023e013c0556d9bec2ec4edcd3891c7bcef1539a7e3c7f"
      },
      "executionMessage": {
        "type": ["string", "null"],
        "description": "Message related to the execution of the order, if any.",
        "example": null
      },
      "intentId": {
        "type": "string",
        "format": "uuid",
        "description": "Unique identifier for the intent associated with the order.",
        "example": "bdecde47-85c1-405d-b2fb-1c971254e0d4"
      },
      "intentMemo": {
        "type": ["string", "null"],
        "description": "Additional memo from the dev associated with the intent.",
        "example": null
      },
      "userId": {
        "type": "string",
        "format": "uuid",
        "description": "Unique identifier for the user who created the order.",
        "example": "41a12c53-aef6-463c-b707-a0c4e79711c9"
      }
    }
  }
}
  • Use the following script to validate Acme signatures included in the headers of each webhook notification:
import crypto, { BinaryToTextEncoding } from "node:crypto";
const fs = require("fs");

const stagePublicKey =
  "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyocie+Q4+AGH7u4ZtpI0\nt+CSsfQiNHvvcWm4ztROV/08Tf3IP2vWFqktZYMPBwQ6z+lYBpOW6NkjWm/eOAkH\nIfWScW59mK2XzeMkBZc03voH4TBZGg5uU/AszuROcDBU344UX4tmbbAVnJP9y8aQ\nIMvVEYa4BOqAEMwRWEAej30slG3tBvilvJTdUMFkN405fnUIVMEjW9shH8mtSSX3\nkw/TW2Y1PB72j64Mw0aBw93vtrKU2UzON9KsOB7Sih56EYnAsPsN1ix42tP0ozyw\nYo02zf6sy59OroeYP0NGNjebYbvQQvSc7/7o4R3/TxKMPAsSsb0EpQjDpodV8jwf\nJQIDAQAB\n-----END PUBLIC KEY-----";

const prodPublicKey =
  "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxn/AHYRfPB5lA2gpV4Hn\nBsvHwY2iRQaEIvX3mOfXqFhzOvGA2aM/klDAhZkZgtkS8AtOIgP0cZ4LsbkYQBIV\nY8YWNy88NNte4rJzO/vtxLHdvgfMIohuduVNhCZAjNPC23nc4/tYsaaW/g0cJaPQ\nfQzM3jit6EQ8Oo0FNu5EZYmPnpusbB0XyTnS6iwF/+YIbkRhwivzJVNS7mO8b8vT\nr5y7eV/KD+CiMC2+/1bTyUTeFI4gtrGoODcNfSCbA7ShtJJoS6AJGx9VOTuML5dD\nzpU75WlG0+mQFqIzO1RtGQWKELxppc5Ws+ZN/0dM5KTaKVdL4TJe+h/K4WZrmHDT\nXv/rBc8nRfPJ6sH+44wNqUJrML6iNFkIh0h1f7Z8tU9inmedg+8bxSCb2xp8XCyV\n2k9+i/j6CQBkC0YzEBJBWl5DK9N5Dq8phrhX8KPuP4uz9O/s3jlBQ478Uqx4csGr\n5ipqijCnzzwbZLRUdf7cJf/tku5Dhnya/n9ENybf/P1N/VN5bjPFfGvkWJxOwjK1\nPeebWudSdyChrSSPhT4WRdssOCucx0bHRA+xgKQX5bAL7mktQLZIbKMjKt3Bdj2e\nFvO4H1eVNziOHVhuCBJxRfju+JPg4JNjGzX3caAd427Gzir8EPoYRpotcd0VEVUV\nwWaV1p6MVdCEC+3z8V6pAD8CAwEAAQ==\n-----END PUBLIC KEY-----";

const publicKey =
  "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArojGIZ5IPLPDSx/AfKW6\nRMxBVhZp7Ze7EnqWGVBe+RxPNW2+vKG+cZ7GdgA/SemkZc6uh0IQSwJoXoZbwr8I\nyDzPSQT9wdO1vltBSE158lb08Pfg7LWUUsXF/H45YCHikyyCvsrbjQEoEoUh25k4\n3pjVa8431xAe4aukrWA+Fl0D4Izkzyzbhhzt4zcmcDzNJoe34hH1zn2fkH+bG/8s\ncuFmZxuAp286SVn0vfUIZj5y4La+FhiFlQCgmxw4TTIwuXZ2MZLYefO31uZ0qa0R\nzy/9S2WRrD4b7K1LKZ8ZSTBF4FfA0v5kBjrpLX4B3SVestMJo5IK1dDUfSKN9bRu\ntwIDAQAB\n-----END PUBLIC KEY-----".replace(
    /\\n/g,
    "\n"
  );

export const DEFAULT_HASH_CONFIG = {
  hashAlgorithm: "sha512",
  signAlgorithm: "RSA-SHA512",
  encodedSignatureAlgorithm: "base64" as BinaryToTextEncoding,
};

export const validateSignature = (params: {
  publicKey: string;
  message: string;
  signature: string;
  config?: {
    hashAlgorithm: "sha512";
    signAlgorithm: "RSA-SHA512";
    encodedSignatureAlgorithm: BinaryToTextEncoding;
  };
}): boolean => {
  const config = params.config ?? DEFAULT_HASH_CONFIG;

  const verifier = crypto.createVerify(config.signAlgorithm);
  const hashedMessage = crypto
    .createHash(config.hashAlgorithm)
    .update(params.message)
    .digest();
  verifier.write(hashedMessage);
  verifier.end();
  const isVerified = verifier.verify(
    params.publicKey,
    params.signature,
    config.encodedSignatureAlgorithm
  );
  return isVerified;
};

//Body taken from notification body
const _message = {
  order: {
    id: "32adfcea-ff26-48ce-a6dc-fbbcc8e68b7d",
    status: "BlockchainTransactionSubmission",
    createdAt: "2024-05-03T02:07:12.003Z",
    blockchainTransactionHash: null,
    executionMessage: null,
    intentId: "8d6f6f80-11f6-48b2-a4e3-615a875928fd",
    intentMemo: null,
    userId: "4cf32778-07a5-4f33-8d58-eaaf41a9aeb4",
  },
};

//Signature taken from notification header -> acme-signature
const _signature =
  "OidfByNLdWowQYcx+w0KSE4utCjJmtZYwO+9fT6K2r6ahpKTgzm/iNwfhvLNxiWfD/1nGHzuOQdWrBqiXbkxZPBLiCpD8dJil2h23agJndd7aXtjqQ5qo64ZE0F+o8hkN/1695s6755G41MTzcucaH0gJo2mAeMG3gzCXQxa7NbmwqU5R8qrP6S8e+G5lcFSW3eT6pc8G+ylHsZusetHUKRMH6xo9sNcwYSCt5NE2yml1NtQYGKGe38L8ehnFbSuCbLRUY3bvBQRQFJhZXCfDOP+C40YdwEtepLrbCJ9fCMd8J/kc03HWICQ5ZjHsmnE/CnHVZ/UOcMIIxKz1AM0dA==";

console.log(
  validateSignature({
    publicKey: publicKey,
    message: JSON.stringify(_message),
    signature: _signature,
  })
);