Technical GuideUpdated September 2026 · 12 min read

Japanese and CJK Document Signing: Unicode, Fontkit, and API Guide (2026)

Sending Japanese, Chinese, or Korean legal agreements from autonomous AI agents requires far more than simply posting UTF-8 strings. Behind the scenes, document compilers must parse unspaced ideographic characters, embed TrueType font metrics via @pdf-lib/fontkit without bloated payloads, and preserve kanji fidelity across tamper-evident SHA-256 audit certificates. Here is how Signbee delivers native Japanese and CJK e-signing via direct REST API and MCP—with zero external SDKs, zero manual template coordinates, and instant verification.

Michael Beckett
Michael Beckett

Founder, Signbee

< 120ms

CJK PDF Render

100%

Unicode Coverage

0

External Font CDNs

SHA-256

Audit Certified

TL;DR — Japanese and CJK Signing Architecture
  • Automated CJK Detection: Signbee inspects incoming payloads with regex /[\u3000-\u9fff\uac00-\ud7af\uff00-\uffef]/ across document markdown, titles, and party names.
  • Native Fontkit TrueType Embedding: When CJK glyphs are present, the PDF compiler registers @pdf-lib/fontkit and embeds ZenKakuGothicNew-Regular.ttf, completely avoiding 8-bit WinAnsi encoding crashes.
  • Token-Aware Line Wrapping: Because Japanese and Chinese prose lacks space delimiters, Signbee tokenizes text character-by-character to measure visual widths and wrap paragraphs naturally without text truncation.
  • Universal Name & Title Support: Party names with kanji (e.g., 佐藤 健一) and corporate designations (e.g., 株式会社サンプル) render cleanly across both the document pages and the SHA-256 audit certificate.
  • Dual Integration (API & MCP): AI agents dispatch contracts either headlessly via POST /api/v1/send or conversationally via signbee-mcp inside Claude Desktop, Cursor, and Windsurf.
  • Legal Enforceability in Japan: Compliant with Japan's Electronic Signature Act (Act No. 102 of 2000), Article 2 and Article 3, as well as global US ESIGN and EU eIDAS Simple Electronic Signature standards.

Watch — Japanese / CJK Document Signing with Signbee — https://www.youtube.com/watch?v=opDeeRzxg2c

The Hidden Complexity of CJK in Document Generation

When autonomous AI agents generate contracts, English and Western European languages benefit from decades of standardized tooling. A typical contract composed in English uses standard Latin-1 character encodings. In lightweight PDF libraries, standard Type 1 PostScript fonts (such as Helvetica, Times Roman, and Courier) do not require font embedding at all—they rely on 14 built-in font definitions present in every PDF reader since 1993.

However, the moment an AI agent drafts a bilingual consulting agreement for a client in Tokyo, an NDA with an engineering partner in Seoul, or an intellectual property assignment with a supplier in Taipei, that entire architecture collapses. Standard 14 PostScript fonts are strictly bounded by the 8-bit WinAnsi (Windows-1252) character set. WinAnsi can only represent characters from code point 0 to 255.

If a backend document compiler attempts to pass a Japanese kanji character like (U+5951, code point 22,865) or a hiragana particle like (U+306E, code point 12,398) to Helvetica, standard PDF engines do one of two disastrous things:

  1. Unhandled Process Crash (HTTP 500): The internal glyph encoder detects a code point exceeding 0x00FF and throws an unhandled encoding exception, crashing the request worker and failing the agent transaction. We detailed our original battle with this in our earlier post-mortem, CJK was a 500. Generate does not count.
  2. Silent Mojibake (???): Engines with naive sanitizers strip non-ASCII bytes or substitute every multibyte character with a question mark. The resulting document looks like ??? (???) instead of 秘密保持契約書 (NDA), rendering the legal agreement completely unusable.

To make digital document signing truly viable for global AI agents, an e-signature infrastructure must provide native, automated multibyte font embedding, CJK-aware typographic line breaking, and flawless audit trail stamping without requiring developers or agents to configure complex font parameters.

Under the Hood: Signbee's CJK Detection & Fontkit Engine

In Signbee's production compiler (src/lib/pdf.ts), every incoming request is inspected before PDF compilation begins. The engine does not require the caller to set a "language": "ja" flag or select a special typography profile. Instead, it inspects the raw payload using an exhaustive Unicode regular expression:

src/lib/pdf.ts — CJK Unicode Detection
export function containsCjk(text: string): boolean {
  if (!text) return false;
  return /[\u3000-\u9fff\uac00-\ud7af\uff00-\uffef]/.test(text);
}

This regular expression scans across six fundamental Unicode blocks critical for East Asian documentation:

  • \u3000-\u303F: CJK Symbols and Punctuation (ideographic space, Japanese brackets 「 」, postal marks, etc.)
  • \u3040-\u309F: Hiragana (phonetic Japanese syllabary used for grammatical particles and native words)
  • \u30A0-\u30FF: Katakana (phonetic Japanese syllabary used for loanwords, technical terms, and foreign names)
  • \u4E00-\u9FFF: CJK Unified Ideographs (over 20,000 common Kanji, Hanzi, and Hanja characters)
  • \uAC00-\uD7AF: Hangul Syllables (complete Korean syllabic blocks)
  • \uFF00-\uFFEF: Halfwidth and Fullwidth Forms (fullwidth Roman letters, numbers, and punctuation)

When containsCjk() evaluates to true, Signbee dynamically engages @pdf-lib/fontkit. Unlike standard font embedding in PDF-lib which only supports AFM (Adobe Font Metrics), Fontkit is an advanced font engine that parses OpenType, TrueType, and WOFF binaries, reading complex glyph tables, kerning pairs, and multibyte character mappings.

In production, Signbee bundles the high-legibility Japanese typeface Zen Kaku Gothic New (specifically stored at src/fonts/ZenKakuGothicNew-Regular.ttf). To eliminate redundant disk I/O across high-frequency API invocations, the binary is cached in memory on the first invocation:

src/lib/pdf.ts — Fontkit Registration and In-Memory Font Caching
let cachedCjkFontBytes: Buffer | null = null;

function getCjkFontBytes(): Buffer | null {
  if (cachedCjkFontBytes) return cachedCjkFontBytes;
  try {
    const fontPath = path.join(process.cwd(), "src/fonts/ZenKakuGothicNew-Regular.ttf");
    if (fs.existsSync(fontPath)) {
      cachedCjkFontBytes = fs.readFileSync(fontPath);
      return cachedCjkFontBytes;
    }
  } catch (err) {
    console.error("Failed to load CJK font from disk:", err);
  }
  return null;
}

// Inside generatePdfBuffer():
if (isCjk) {
  const cjkBytes = getCjkFontBytes();
  if (cjkBytes) {
    pdfDoc.registerFontkit(fontkit);
    const cjkFont = await pdfDoc.embedFont(cjkBytes, { subset: false });
    font = cjkFont;
    fontBold = cjkFont;
    fontItalic = cjkFont;
  }
}

By registering fontkit and embedding ZenKakuGothicNew-Regular.ttf directly into the PDF container, the document becomes completely self-contained. The recipient can open the executed agreement on an iPhone in Osaka, a Linux server in Frankfurt, or a Windows desktop in Chicago, and every single kanji, hiragana, and katakana character renders identically with razor-sharp vector clarity.

Token-Aware Word Wrapping Without Whitespace

Font embedding solves character rendering, but it introduces a secondary typographic obstacle: line wrapping. In English, word wrapping is trivially achieved by splitting a paragraph on space characters (text.split(" ")), accumulating words until the line width exceeds the page margin, and pushing the overflow to the next line.

Japanese, however, is written without word spaces. A sentence like:

甲及び乙は、本契約に定める業務の遂行にあたり知り得た相手方の営業上または技術上の秘密情報を、相手方の書面による事前の承諾なしに第三者に開示または漏洩してはならない。

contains zero spaces. If you pass this string to an English text-wrapping function, the entire 80-character sentence is treated as a single monolithic word. The wrapper attempts to measure the whole line, discovers it exceeds the 495pt printable content width, and either pushes it entirely off the right margin into oblivion or breaks it in arbitrary, corrupted increments.

To solve this, Signbee's wrapText() function switches to a CJK-aware tokenizer when multibyte text is present:

src/lib/pdf.ts — CJK Tokenizer and Width Measurement
function wrapText(
  text: string,
  font: PDFFont,
  fontSize: number,
  maxWidth: number,
  isCjk: boolean = false
): string[] {
  if (!isCjk) {
    // Standard Latin space-delimited wrapping...
    const words = text.split(" ");
    /* ... */
  }

  // CJK-aware character and token wrapping
  const lines: string[] = [];
  const paragraphs = text.split("\n");

  for (const para of paragraphs) {
    let currentLine = "";
    // Match individual CJK characters OR consecutive alphanumeric words
    const tokens = para.match(
      /[\u3000-\u9fff\uac00-\ud7af\uff00-\uffef]|[\w'-]+|[^\s\w]/gu
    ) || [para];

    for (const token of tokens) {
      const isTokenCjk = /[\u3000-\u9fff\uac00-\ud7af\uff00-\uffef]/.test(token);
      const isLastCjk = currentLine && /[\u3000-\u9fff\uac00-\ud7af\uff00-\uffef]/.test(currentLine.slice(-1));
      
      // Separate Latin words with spaces, but join CJK ideographs seamlessly
      const needsSpace = currentLine && !isLastCjk && !isTokenCjk && !/^[.,!?;:]/.test(token);
      const separator = needsSpace ? " " : "";
      const testLine = currentLine ? `${currentLine}${separator}${token}` : token;
      
      let width = 0;
      try {
        width = font.widthOfTextAtSize(testLine, fontSize);
      } catch {
        width = maxWidth + 1;
      }

      if (width > maxWidth && currentLine) {
        lines.push(currentLine);
        currentLine = token;
      } else {
        currentLine = testLine;
      }
    }
    if (currentLine) lines.push(currentLine);
  }
  return lines;
}

This dual-tokenizer architecture provides two essential capabilities:

  • Clean Character Breaks: Japanese characters wrap smoothly at the exact right margin without breaking mid-word when English terms (like "Signbee" or "API") appear within the Japanese clause.
  • Table Cell Calculation: In Markdown pipe tables (e.g. fee schedules or milestone deliverable tables), column widths are calculated cleanly, truncating or wrapping cells gracefully without throwing font measurement exceptions.

API Guide: Sending Japanese Contracts via POST /api/v1/send

Sending a Japanese document via Signbee requires zero custom headers, zero font configuration flags, and zero template setup. The agent simply dispatches an HTTP POST request to https://signb.ee/api/v1/send with standard UTF-8 JSON.

Here is a complete, production-ready cURL command demonstrating a standard Japanese Master Service Agreement (業務委託基本契約書) between two fictional corporate entities:

Terminal — POST /api/v1/send with Japanese Markdown
curl -X POST https://signb.ee/api/v1/send \
  -H "Content-Type: application/json; charset=utf-8" \
  -H "Authorization: Bearer sbe_live_your_api_key_here" \
  -d '{
    "document": "# 業務委託基本契約書\n\n発注者:**株式会社サンプル**(以下「甲」という)と、受注者:**株式会社テクノロジー**(以下「乙」という)は、業務委託に関して次のとおり契約を締結する。\n\n## 第1条(目的)\n甲は乙に対し、AIエージェントインフラストラクチャの開発および保守業務(以下「本業務」という)を委託し、乙はこれを受託する。\n\n## 第2条(委託料及び支払条件)\n1. 本業務の委託料は、月額金500,000円(消費税別)とする。\n2. 甲は、毎月末日締めの翌月末日までに、乙の指定する銀行口座に振込送金して支払う。\n\n## 第3条(秘密保持)\n甲および乙は、本業務の遂行により知り得た相手方の技術上、営業上の秘密情報を、事前の書面承諾なく第三者に開示または漏洩してはならない。\n\n## 第4条(契約期間)\n本契約の有効期間は、契約締結の日から1年間とする。\n\n| 項目 | 内容 | 納期 |\n| :--- | :--- | :--- |\n| フェーズ1 | 要件定義及びAPI設計 | 2026年10月15日 |\n| フェーズ2 | コアエンジン実装 | 2026年11月30日 |\n| フェーズ3 | 検収及び本番展開 | 2026年12月20日 |\n\n本契約の成立を証するため、本書を電磁的記録として作成し、甲乙合意の上電子署名を付す。",
    "parties": [
      {
        "name": "佐藤 健一",
        "email": "sato@example.co.jp"
      },
      {
        "name": "田中 太郎",
        "email": "tanaka@example.jp"
      }
    ]
  }'

Notice how the payload handles every level of Japanese documentation naturally:

  • Document Title: The Markdown # 業務委託基本契約書 heading is extracted automatically as the formal document title.
  • Party Signatory Names: The parties array contains full Kanji personal names (佐藤 健一 and 田中 太郎). These names are mapped into the signing ceremony UI and the permanent audit trail.
  • Markdown Tables: The three-column Japanese table (項目 | 内容 | 納期) is formatted and measured with Zen Kaku Gothic New metrics.
  • Instant Response: The API responds within ~120ms with HTTP 200 containing the generated document UUID, status "pending", and public signing URLs.

Zero-Friction Email OTP vs Instant API Key Authentication

Like all Signbee endpoints, you do not need an account or an API key to test Japanese contract dispatch. If you omit the Authorization header, Signbee triggers its zero-friction developer onboarding flow:

  1. Signbee compiles the Japanese PDF in memory.
  2. Signbee dispatches a secure 6-digit One-Time Password (OTP) to the sender's email address.
  3. The API returns an OTP verification prompt. Once verified, the signing links are dispatched immediately to both parties.

When deploying autonomous AI agents in production (e.g. background workers built with LangGraph, CrewAI, or AutoGen), providing your SIGNBEE_API_KEY completely bypasses OTP verification, executing the dispatch headlessly in a single turn. For a detailed architectural breakdown of this single-call paradigm, read One API Call: Markdown to Signed PDF for AI Agents.

Dispatching Japanese Contracts from Claude Desktop & MCP

For conversational AI assistants like Claude Desktop, Cursor, and Windsurf, Signbee publishes an official Model Context Protocol server (signbee-mcp). You can configure it in 90 seconds by adding a single entry to your claude_desktop_config.json:

claude_desktop_config.json — Adding Signbee MCP
{
  "mcpServers": {
    "signbee": {
      "command": "npx",
      "args": ["-y", "signbee-mcp"],
      "env": {
        "SIGNBEE_API_KEY": "sbe_live_your_api_key_here"
      }
    }
  }
}

Once configured, Claude has access to the send_document tool. You can prompt Claude directly in Japanese:

「株式会社サンプル(佐藤健一様 sato@example.co.jp)と弊社(田中太郎 tanaka@example.jp)の間で、月額50万円のAI開発に関する秘密保持契約書(NDA)を作成し、電子署名用に送信してください。」

Claude drafts the complete legal agreement in Japanese Markdown and invokes send_document:

Claude MCP Tool Call — send_document
// Claude Desktop autonomously invokes send_document:
{
  "document": "# 秘密保持契約書\n\n株式会社サンプル(以下「甲」という)と田中太郎(以下「乙」という)は...\n\n## 第1条(秘密情報)\n...",
  "parties": [
    { "name": "佐藤 健一", "email": "sato@example.co.jp" },
    { "name": "田中 太郎", "email": "tanaka@example.jp" }
  ]
}

The Signbee MCP server pipes the payload directly to the REST API. Claude receives the document ID and signing links back in chat, confirming that dispatch succeeded. For a complete guide to configuring MCP with step-by-step screenshots and video walkthroughs, see Claude Desktop Signbee MCP Setup: Send Your First E-Sign Document.

Japanese Signatory Names on the SHA-256 Audit Certificate

A common flaw in legacy e-signature systems is that while the contract body might render non-Latin characters, the final audit certificate page fails. When the counter-parties complete their signing ceremonies, the system stamps a "Certificate of Completion" or "Audit Trail" using a rigid, hardcoded Helvetica template. As a result, the signer's name appears as ??? ??? or unrendered hex entities.

In Signbee, the certificate generator (src/lib/signing-certificate.ts) applies the exact same CJK Unicode intelligence to the cryptographic certification page:

src/lib/signing-certificate.ts — CJK Stamping on Audit Certificates
export async function appendSigningCertificate(
  pdfBytes: Buffer | Uint8Array,
  data: SigningCertificateData
): Promise<Uint8Array> {
  const pdfDoc = await PDFDocument.load(pdfBytes);
  const page = pdfDoc.addPage([595, 842]); // A4

  // Detect CJK across title and party names:
  const isCjk = containsCjk(`${data.title} ${data.senderName} ${data.recipientName}`);

  let helvetica: PDFFont;
  if (isCjk) {
    const cjkBytes = getCjkFontBytes();
    if (cjkBytes) {
      pdfDoc.registerFontkit(fontkit);
      const cjkFont = await pdfDoc.embedFont(cjkBytes, { subset: false });
      helvetica = cjkFont;
    }
  }
  /* ... stamp certificate with SHA-256, UTC timestamps, IP addresses ... */
}

When both parties sign, Signbee compiles the executed document, hashes the binary using SHA-256, and appends a dedicated A4 certificate page. The certificate cleanly displays:

  • Document Title: 業務委託基本契約書 (rendered in Zen Kaku Gothic New)
  • Sender Party: 株式会社サンプル / 佐藤 健一 (verified via email OTP & IP address)
  • Recipient Party: 株式会社テクノロジー / 田中 太郎 (signed via web canvas & IP log)
  • Cryptographic Hash: SHA-256 checksum (e.g. e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)
  • Tamper-Evident Verification URL: Permanent verification link to confirm hash integrity at any future date

Legal Enforceability in Japan: Act on Electronic Signatures

In Japan, electronic contracting is governed primarily by the Act on Electronic Signatures and Certification Services (電子署名及び認証業務に関する法律, Act No. 102 of 2000, commonly referred to as theElectronic Signature Act or Denshi Shomei Hō).

Under Article 2 of the Act, an electronic signature is legally recognized if:

  1. It indicates that the recorded information was created or approved by the designated signatory.
  2. It incorporates measures to detect any subsequent alteration or tampering of the recorded information.

Furthermore, under Article 3, an electronic document is presumed to be authentically executed (真正に成立したものと推定する) if an electronic signature is attached that could only have been performed by the principal party. In 2020, the Japanese Ministry of Economy, Trade and Industry (METI), Ministry of Justice (MOJ), and Ministry of Internal Affairs and Communications (MIC) issued landmark joint interpretive guidelines clarifying that cloud-based, two-party signature services utilizing email authentication, tamper-evident audit logs, and cryptographic hashing satisfy the evidentiary thresholds for valid contract execution in Japanese civil litigation.

Signbee provides exactly this evidentiary foundation:

  • Signer Intent: Explicit digital consent captured through a responsive web ceremony where parties view the rendered Japanese terms and affix their signature.
  • Identity Attribution: Multi-factor verification via unique secure email dispatch tokens, optional sender OTP verification, UTC timestamps, and client IP/user-agent logging.
  • Tamper Evidence: An immutable SHA-256 cryptographic hash calculated immediately upon final signature, permanently binding the document terms to the audit trail. Any subsequent byte modification breaks the cryptographic verification hash.

This ensures that Japanese agreements executed via Signbee are fully enforceable under Japanese law, while simultaneously satisfying the US ESIGN Act, the UK Electronic Communications Act 2000, and the European Union eIDAS regulation for Simple Electronic Signatures (SES).

Technical Comparison: Signbee vs Alternative Approaches

When engineering teams attempt to build Japanese and CJK document generation in-house or evaluate third-party APIs, they encounter severe architectural trade-offs between speed, bundle size, and rendering reliability. The following table contrasts the most common approaches:

ArchitectureCJK SupportCold-Start LatencyMemory / FootprintSetup Complexity
Signbee API (Fontkit + TTF)Native & Automated< 120ms~2.3MB (in-memory cache)Zero (Single POST)
Headless Chrome / PuppeteerRequires OS font packages1,500ms - 3,500ms150MB - 350MB RAM / browser instanceHigh (Chromium binary, Docker)
Standard PDF-Lib (Helvetica)Fails (WinAnsi crash / 500)< 50ms< 1MBUnusable for Asian languages
Legacy E-Sign APIs (DocuSign, Adobe)Requires pre-rendered PDF800ms - 2,000msRemote Cloud EnvelopeVery High (OAuth, x/y coords, SDKs)

By combining @pdf-lib/fontkit with in-memory caching of ZenKakuGothicNew-Regular.ttf, Signbee achieves sub-120 millisecond rendering speeds while maintaining a microscopic memory footprint that runs reliably inside serverless edge workers and containerized microservices.

Troubleshooting & Developer Best Practices

When integrating Japanese and CJK contract generation into autonomous pipelines, adhere to the following engineering practices to avoid common data corruption and formatting bugs:

1. Enforce UTF-8 Content-Type Headers

Always include charset=utf-8 in your HTTP request headers:

Content-Type: application/json; charset=utf-8

Some older HTTP clients and proxy gateways default to ISO-8859-1 if the charset is unspecified, mutilating multibyte kanji bytes before they reach the API gateway.

2. Test Layouts Locally with POST /api/v1/generate

To preview how complex Japanese tables, bulleted lists, and section breaks render without dispatching emails or consuming your monthly signing quota, use the dedicated preview endpoint:

POST https://signb.ee/api/v1/generate

POST /api/v1/generate accepts the exact same document markdown payload and returns the raw compiled PDF binary stream. It does not create signing records or deduct document quota, allowing you to iterate on typography and layout completely free of charge. Learn more in Markdown to Signed PDF API: Send Contracts in One POST Request.

3. Avoid Unescaped Control Characters in JSON Payloads

When constructing raw JSON payloads programmatically, ensure newlines in your Markdown text are properly escaped as \n. Many programming languages offer native JSON serialization (e.g. JSON.stringify() in JavaScript or json.dumps() in Python), which properly handles UTF-8 string encoding and newline escaping automatically.

Get Started with Japanese E-Signing Today

Whether you are building an autonomous sales agent that closes international B2B agreements, an HR onboarding pipeline for Japanese subsidiaries, or an AI legal assistant in Claude Desktop, Signbee eliminates every barrier to CJK document signing.

Related resources