Mint Inscriptions Endpoint

Learn how to mint ordinal inscriptions and BSV21 tokens from your Droplit instance.

Mint Inscriptions Endpoint

This endpoint allows you to mint ordinal inscriptions or BSV21 tokens using funds from your Droplit instance. The inscription data is encoded on-chain and sent to the specified recipient address.

  • Endpoint: POST /faucet/{droplitName}/mint
    • Replace {droplitName} with the name of your Droplit.
  • Authentication: Required (see Authentication)

Request Body

The request body must be a JSON object with the following structure:

{
  "recipientAddress": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "contentType": "text/plain",
  "data": "Hello, Ordinals!",
  "encoding": "utf8",
  "feeRate": 100,
  "broadcast": true,
  "bsv21": {
    "ticker": "SATS",
    "max": "21000000",
    "limit": "1000",
    "dec": 8
  }
}

Required Fields

  • recipientAddress (string): BSV address that will receive the inscription.
  • contentType (string): MIME type of the inscription data.
    • Examples: "text/plain", "application/json", "image/png", "application/bsv-20"
  • data (string): The inscription content. Encoding depends on the encoding field.

Optional Fields

  • encoding (string): Encoding format for the data field. Default: "utf8"
    • "utf8": UTF-8 text data
    • "base64": Base64-encoded binary data (for images, etc.)
    • "hex": Hex-encoded binary data
  • feeRate (number): Fee rate in satoshis per kilobyte. Default: 100
  • broadcast (boolean): Whether to broadcast the transaction immediately. Default: true
  • bsv21 (object): Optional BSV21 token metadata. Include this to mint a token:
    • ticker (string): Token ticker symbol (e.g., "SATS")
    • max (string): Maximum token supply (use string for large numbers)
    • limit (string): Maximum minting amount per transaction
    • dec (number): Number of decimal places (0-8)

Inscription Types

Text Inscription

Simple text inscriptions for messages, notes, or data:

{
  "recipientAddress": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "contentType": "text/plain",
  "data": "Hello, Ordinals!",
  "encoding": "utf8",
  "feeRate": 100,
  "broadcast": true
}

JSON Inscription

Structured data inscriptions:

{
  "recipientAddress": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "contentType": "application/json",
  "data": "{\"title\": \"My NFT\", \"description\": \"This is metadata\"}",
  "encoding": "utf8",
  "feeRate": 100,
  "broadcast": true
}

Image Inscription

Binary image data must be base64-encoded:

{
  "recipientAddress": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "contentType": "image/png",
  "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
  "encoding": "base64",
  "feeRate": 100,
  "broadcast": true
}

BSV21 Token

To mint a BSV21 token, include the bsv21 metadata:

{
  "recipientAddress": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "contentType": "application/bsv-20",
  "data": "{}",
  "encoding": "utf8",
  "feeRate": 100,
  "broadcast": true,
  "bsv21": {
    "ticker": "SATS",
    "max": "21000000",
    "limit": "1000",
    "dec": 8
  }
}

Example: Curl

Replace <YOUR_WIF>, <DROPLIT_NAME>, <GENERATED_AUTH_TOKEN_VALUE>, and <YOUR_DROPLIT_API_URL> with your actual values.

# 1. Define variables
PAYLOAD_BODY='{
  "recipientAddress": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "contentType": "text/plain",
  "data": "Hello, Ordinals!",
  "encoding": "utf8",
  "feeRate": 100,
  "broadcast": true
}'
PATHNAME_VALUE="/faucet/<DROPLIT_NAME>/mint"
# Note: For the AUTH_TOKEN_VALUE, you need to generate it using a bitcoin-auth library.
# The message to sign is: PATHNAME_VALUE + PAYLOAD_BODY
AUTH_TOKEN_VALUE="<GENERATED_AUTH_TOKEN_VALUE>"
YOUR_DROPLIT_API_URL="http://localhost:8080" # Or your deployed URL
DROPLIT_NAME="your-droplit-name"

# 2. Make the request
curl -X POST \
  -H "Content-Type: application/json" \
  -H "X-Auth-Token: ${AUTH_TOKEN_VALUE}" \
  -d "${PAYLOAD_BODY}" \
  ${YOUR_DROPLIT_API_URL}/faucet/${DROPLIT_NAME}/mint

Example: JavaScript (Node.js using node-fetch and bitcoin-auth)

import fetch from 'node-fetch';
import { AuthConfig, getAuthToken } from 'bitcoin-auth';

async function mintInscription() {
  const droplitName = "your-droplit-name"; // Replace
  const userWIF = "your-private-key-wif"; // Replace
  const droplitApiUrl = "http://localhost:8080"; // Replace with your API URL

  const requestPath = `/faucet/${droplitName}/mint`;
  const payload = {
    recipientAddress: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", // Replace
    contentType: "text/plain",
    data: "Hello from Droplit!",
    encoding: "utf8",
    feeRate: 10,
    broadcast: true,
  };
  const bodyString = JSON.stringify(payload);

  const authConfig: AuthConfig = {
    privateKeyWif: userWIF,
    requestPath: requestPath,
    body: bodyString,
  };

  try {
    const authToken = await getAuthToken(authConfig);
    console.log('Auth Token:', authToken);

    const response = await fetch(`${droplitApiUrl}${requestPath}`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Auth-Token": authToken,
      },
      body: bodyString,
    });

    let responseData;
    const contentType = response.headers.get("content-type");
    if (contentType && contentType.includes("application/json")) {
      responseData = await response.json();
    } else {
      responseData = await response.text();
    }

    if (!response.ok) {
      console.error('API Error:', responseData);
      throw new Error(`HTTP error! Status: ${response.status} - ${responseData}`);
    }

    console.log("Mint successful:", responseData);
    // Expected response includes inscriptionId, txid, fee, etc.
  } catch (error) {
    console.error("Error minting inscription:", error);
  }
}

mintInscription();

Example: Minting an Image

import fs from 'fs';

async function mintImage() {
  const droplitName = "your-droplit-name";
  const userWIF = "your-private-key-wif";
  const droplitApiUrl = "http://localhost:8080";

  // Read image file and convert to base64
  const imageBuffer = fs.readFileSync('./my-image.png');
  const base64Image = imageBuffer.toString('base64');

  const requestPath = `/faucet/${droplitName}/mint`;
  const payload = {
    recipientAddress: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    contentType: "image/png",
    data: base64Image,
    encoding: "base64",
    feeRate: 10,
    broadcast: true,
  };
  const bodyString = JSON.stringify(payload);

  const authConfig: AuthConfig = {
    privateKeyWif: userWIF,
    requestPath: requestPath,
    body: bodyString,
  };

  const authToken = await getAuthToken(authConfig);
  const response = await fetch(`${droplitApiUrl}${requestPath}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Auth-Token": authToken,
    },
    body: bodyString,
  });

  const responseData = await response.json();
  console.log("Image inscribed:", responseData);
}

Example: Minting a BSV21 Token

async function mintBSV21Token() {
  const droplitName = "your-droplit-name";
  const userWIF = "your-private-key-wif";
  const droplitApiUrl = "http://localhost:8080";

  const requestPath = `/faucet/${droplitName}/mint`;
  const payload = {
    recipientAddress: "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    contentType: "application/bsv-20",
    data: JSON.stringify({ description: "My awesome token" }),
    encoding: "utf8",
    feeRate: 10,
    broadcast: true,
    bsv21: {
      ticker: "MYTOKEN",
      max: "1000000",
      limit: "100",
      dec: 8,
    },
  };
  const bodyString = JSON.stringify(payload);

  const authConfig: AuthConfig = {
    privateKeyWif: userWIF,
    requestPath: requestPath,
    body: bodyString,
  };

  const authToken = await getAuthToken(authConfig);
  const response = await fetch(`${droplitApiUrl}${requestPath}`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Auth-Token": authToken,
    },
    body: bodyString,
  });

  const responseData = await response.json();
  console.log("Token minted:", responseData);
}

Success Response

On success, the API returns a JSON object with details about the minted inscription:

{
  "success": true,
  "txid": "abcdef123456...",
  "inscriptionId": "abcdef123456..._0",
  "outputIndex": 0,
  "fee": 150,
  "size": 250,
  "feeRate": 100,
  "broadcasted": true,
  "contentType": "text/plain",
  "inscriptionSize": 18
}

Response Fields

  • success (boolean): Always true on success
  • txid (string): Transaction ID of the inscription transaction
  • inscriptionId (string): Unique inscription identifier (txid + output index)
  • outputIndex (number): Output index containing the inscription
  • fee (number): Total transaction fee in satoshis
  • size (number): Transaction size in bytes
  • feeRate (number): Actual fee rate used (satoshis per byte)
  • broadcasted (boolean): Whether the transaction was broadcast to the network
  • contentType (string): MIME type of the inscribed content
  • inscriptionSize (number): Size of the inscription data in bytes

Error Responses

Common errors include:

400 Bad Request

Invalid request parameters or inscription data:

{
  "success": false,
  "error": "invalid_request",
  "message": "Recipient address is required"
}

401 Unauthorized

Missing or invalid authentication token:

{
  "success": false,
  "error": "unauthorized",
  "message": "Invalid or missing X-Auth-Token"
}

402 Payment Required

Insufficient balance in Droplit:

{
  "success": false,
  "error": "insufficient_funds",
  "message": "Not enough balance to mint inscription",
  "details": {
    "availableSatoshis": 1000,
    "requiredSatoshis": 5000
  }
}

413 Payload Too Large

Inscription data exceeds size limits:

{
  "success": false,
  "error": "inscription_too_large",
  "message": "Inscription data exceeds maximum size",
  "details": {
    "inscriptionTooLarge": true,
    "maxSize": 500000
  }
}

422 Unprocessable Entity

Invalid content type or encoding:

{
  "success": false,
  "error": "invalid_content",
  "message": "Invalid content type for inscription",
  "details": {
    "invalidContentType": true
  }
}

500 Internal Server Error

Server-side issue during minting:

{
  "success": false,
  "error": "server_error",
  "message": "Failed to create inscription transaction"
}

Best Practices

  1. Check Balance First: Ensure your Droplit has sufficient funds before minting. Each inscription requires:

    • Inscription output (546 satoshis minimum)
    • Transaction fees (typically 150-500 satoshis depending on size)
  2. Optimize Image Size: For image inscriptions, compress images before uploading:

    • Keep images under 500KB for reasonable fees
    • Use PNG or WebP for best compression
    • Consider reducing resolution for large images
  3. Validate JSON: Always validate JSON data before sending to ensure it's properly formatted.

  4. Use Appropriate Content Types: Choose the correct MIME type:

    • Text: text/plain
    • JSON: application/json
    • Images: image/png, image/jpeg, image/webp, image/svg+xml
    • BSV21 tokens: application/bsv-20
  5. Handle Errors Gracefully: Check the success field in responses and handle errors appropriately:

    if (response.success) {
      console.log(`Inscription created: ${response.inscriptionId}`);
    } else {
      console.error(`Error: ${response.message}`);
    }
  6. Test with Small Inscriptions: Start with small text inscriptions to verify your setup before minting larger images or tokens.

  7. Monitor Transaction Confirmations: After broadcasting, monitor the transaction on a block explorer to ensure it's confirmed on-chain.

Fee Estimation

Inscription fees depend on:

  • Inscription Size: Larger content costs more
  • Fee Rate: Higher rates get faster confirmation
  • Network Conditions: Congestion may require higher fees

Typical fee ranges:

  • Small text (< 100 bytes): 150-300 satoshis
  • Medium JSON (100-1000 bytes): 300-1500 satoshis
  • Large image (10-100KB): 1500-50000 satoshis
  • BSV21 token: 500-1000 satoshis

Use the response fee field to track actual costs for budgeting.