<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Preecha</title>
    <description>The latest articles on DEV Community by Preecha (@preecha).</description>
    <link>https://dev.to/preecha</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3891818%2Ffc0ea1ab-a477-4892-93a0-711e6f361ce2.png</url>
      <title>DEV Community: Preecha</title>
      <link>https://dev.to/preecha</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/preecha"/>
    <language>en</language>
    <item>
      <title>What Is the Model Context Protocol (MCP) and Why Does It Matter for APIs?</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Sat, 29 Aug 2026 14:01:24 +0000</pubDate>
      <link>https://dev.to/preecha/what-is-the-model-context-protocol-mcp-and-why-does-it-matter-for-apis-45lo</link>
      <guid>https://dev.to/preecha/what-is-the-model-context-protocol-mcp-and-why-does-it-matter-for-apis-45lo</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Model Context Protocol (MCP) is a standard for connecting AI assistants to external data sources and APIs. It lets Claude Desktop, Cursor, and other AI tools access your API securely. Modern PetstoreAPI implements MCP so AI assistants can search pets, place orders, and manage inventory through natural language.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Imagine asking Claude Desktop:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show me available cats under $300.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Without API access, Claude might respond that it cannot access your pet store data. You would then need to query the API manually and paste the results into the conversation.&lt;/p&gt;

&lt;p&gt;With MCP, Claude can call your API through an MCP server. The same request becomes an automated workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Claude identifies the required tool.&lt;/li&gt;
&lt;li&gt;It calls &lt;code&gt;search_pets&lt;/code&gt; with the appropriate filters.&lt;/li&gt;
&lt;li&gt;The MCP server queries PetstoreAPI.&lt;/li&gt;
&lt;li&gt;Claude formats the response for the user.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Modern PetstoreAPI implements MCP, allowing AI assistants to interact with the pet store through natural language.&lt;/p&gt;

&lt;p&gt;If you’re building APIs for AI integration, Apidog helps you test MCP implementations and validate AI assistant interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is MCP?
&lt;/h2&gt;

&lt;p&gt;MCP is a protocol created by Anthropic for connecting AI assistants to external resources and tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem MCP Solves
&lt;/h3&gt;

&lt;p&gt;AI assistants are powerful but isolated. Without an integration layer, they cannot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access your company’s internal APIs&lt;/li&gt;
&lt;li&gt;Query your database&lt;/li&gt;
&lt;li&gt;Read files from your filesystem&lt;/li&gt;
&lt;li&gt;Interact with external services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MCP provides a standard way for AI assistants to connect to these resources while keeping authentication and API access in the MCP server.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Components
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;MCP server&lt;/strong&gt; — Exposes resources and tools to AI assistants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP client&lt;/strong&gt; — The AI assistant, such as Claude Desktop or Cursor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources&lt;/strong&gt; — Data the AI can read, including files, database records, and API responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt; — Actions the AI can perform, such as creating an order, updating a pet, or searching inventory.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  MCP Architecture
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Assistant (Claude Desktop)
    ↓ MCP Protocol
MCP Server (PetstoreAPI MCP Server)
    ↓ Internal APIs
PetstoreAPI Backend
    ↓
Database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How MCP Works
&lt;/h2&gt;

&lt;p&gt;An MCP integration typically follows three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Register the MCP server with the AI client.&lt;/li&gt;
&lt;li&gt;Expose the available tools and their input schemas.&lt;/li&gt;
&lt;li&gt;Execute a tool when the assistant determines that it is needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Register the MCP Server
&lt;/h3&gt;

&lt;p&gt;For example, configure Claude Desktop to start a local MCP server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"petstore"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/path/to/petstore-mcp-server.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"PETSTORE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-api-key"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The configuration tells the client:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which command starts the server&lt;/li&gt;
&lt;li&gt;Where the server entry point is located&lt;/li&gt;
&lt;li&gt;Which environment variables the server needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep credentials in environment variables rather than hard-coding them in the server source.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Expose Tools and Schemas
&lt;/h3&gt;

&lt;p&gt;The AI client can discover the tools exposed by the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tools"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_pets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Search for pets by species, status, and price"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"species"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"CAT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DOG"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"maxPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"number"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"AVAILABLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ADOPTED"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"create_order"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Place an order for a pet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"inputSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"petId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"petId"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool schema is important because it tells the assistant:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which operations are available&lt;/li&gt;
&lt;li&gt;What each tool does&lt;/li&gt;
&lt;li&gt;Which arguments it accepts&lt;/li&gt;
&lt;li&gt;Which arguments are required&lt;/li&gt;
&lt;li&gt;Which values are valid for enum fields&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep descriptions specific. A clear description helps the assistant select the correct tool and construct valid arguments.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Execute a Tool Call
&lt;/h3&gt;

&lt;p&gt;When the user asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Show me available cats under $300.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The assistant can translate that request into a tool call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_pets"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"species"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CAT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AVAILABLE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"maxPrice"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server then maps the tool arguments to the underlying API request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;search_pets&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;species&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxPrice&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;species&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;maxPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxPrice&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;`https://petstoreapi.com/v1/pets?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server returns the API response to the assistant, which formats the results for the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  MCP vs. Traditional APIs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Traditional API&lt;/th&gt;
&lt;th&gt;MCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Access&lt;/td&gt;
&lt;td&gt;Direct HTTP&lt;/td&gt;
&lt;td&gt;Through an AI assistant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interface&lt;/td&gt;
&lt;td&gt;REST or GraphQL&lt;/td&gt;
&lt;td&gt;Natural language&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Authentication&lt;/td&gt;
&lt;td&gt;API keys or OAuth&lt;/td&gt;
&lt;td&gt;MCP server handles authentication&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Discovery&lt;/td&gt;
&lt;td&gt;OpenAPI documentation&lt;/td&gt;
&lt;td&gt;Tool schemas&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Usage&lt;/td&gt;
&lt;td&gt;Code or &lt;code&gt;curl&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Conversational requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Error handling&lt;/td&gt;
&lt;td&gt;HTTP status codes&lt;/td&gt;
&lt;td&gt;AI interprets and presents errors&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;MCP does not replace the underlying API. It adds an AI-oriented interface on top of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example Comparison
&lt;/h3&gt;

&lt;p&gt;A direct API request might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer token"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://petstoreapi.com/v1/pets?species=CAT&amp;amp;maxPrice=300"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The equivalent MCP interaction is conversational:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User: Show me available cats under $300

AI: Calls search_pets with:
    species = CAT
    status = AVAILABLE
    maxPrice = 300

AI: Here are 5 available cats under $300:
    1. Fluffy - $250
    2. Whiskers - $280
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API still performs the search. MCP provides the discovery and interaction layer that allows the assistant to invoke it.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Modern PetstoreAPI Implements MCP
&lt;/h2&gt;

&lt;p&gt;Modern PetstoreAPI provides an MCP server that exposes pet-store operations as tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Available Tools
&lt;/h3&gt;

&lt;p&gt;The available tools include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;search_pets&lt;/code&gt; — Search pets by criteria&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_pet&lt;/code&gt; — Get pet details&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;create_order&lt;/code&gt; — Place an order&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;get_inventory&lt;/code&gt; — Check inventory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;update_pet_status&lt;/code&gt; — Update pet availability&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Example: Search and Order
&lt;/h3&gt;

&lt;p&gt;A request such as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find me a dog under $500 and place an order&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;should be handled as a multi-step workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call &lt;code&gt;search_pets({ species: "DOG", maxPrice: 500 })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Show the matching results to the user.&lt;/li&gt;
&lt;li&gt;Wait for confirmation, such as: &lt;code&gt;Order the Labrador&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;create_order({ petId: "019b4132", userId: "user-456" })&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm that the order was placed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Separating search from order creation gives the user an opportunity to review and confirm the selected pet before an action is performed.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP Server Code
&lt;/h3&gt;

&lt;p&gt;The following server uses the MCP SDK and a standard input/output transport:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Server&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/index.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StdioServerTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@modelcontextprotocol/sdk/server/stdio.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;petstore-mcp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/list&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_pets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search for pets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;inputSchema&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;species&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;maxPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setRequestHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_pets&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="s2"&gt;`https://petstoreapi.com/v1/pets?&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StdioServerTransport&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The implementation has two important handlers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;tools/list&lt;/code&gt; publishes the tools and their schemas.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tools/call&lt;/code&gt; executes the selected tool and returns the result.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a production implementation, add validation for tool names and arguments, and map API failures to clear tool responses.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing MCP with Apidog
&lt;/h2&gt;

&lt;p&gt;Use Apidog to test the API and MCP integration in separate stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the Underlying API
&lt;/h3&gt;

&lt;p&gt;First verify that the API endpoints work independently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search pets with valid filters.&lt;/li&gt;
&lt;li&gt;Retrieve pet details.&lt;/li&gt;
&lt;li&gt;Create orders with valid identifiers.&lt;/li&gt;
&lt;li&gt;Test invalid query parameters.&lt;/li&gt;
&lt;li&gt;Confirm authentication behavior.&lt;/li&gt;
&lt;li&gt;Check response formats and error status codes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Validate the MCP Layer
&lt;/h3&gt;

&lt;p&gt;Then verify that the MCP server correctly exposes and invokes those operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Confirm every expected operation appears in &lt;code&gt;tools/list&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check that tool names and descriptions are accurate.&lt;/li&gt;
&lt;li&gt;Validate required and optional input fields.&lt;/li&gt;
&lt;li&gt;Confirm enum values match the API contract.&lt;/li&gt;
&lt;li&gt;Verify tool arguments map to the correct API parameters.&lt;/li&gt;
&lt;li&gt;Test authentication failures.&lt;/li&gt;
&lt;li&gt;Test API errors and malformed tool input.&lt;/li&gt;
&lt;li&gt;Confirm returned data is formatted as valid tool content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Testing both layers makes it easier to determine whether a failure comes from the API contract, the MCP schema, or the tool execution logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why MCP Matters
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. AI-Native APIs
&lt;/h3&gt;

&lt;p&gt;APIs become accessible through natural language. Non-technical users can interact with your API through supported AI assistants.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Standardization
&lt;/h3&gt;

&lt;p&gt;MCP provides a standard approach to AI and API integration. You can expose your operations through MCP instead of building a separate custom integration for every AI client.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Security
&lt;/h3&gt;

&lt;p&gt;MCP servers handle authentication. AI assistants do not need direct access to the API keys used by the underlying service.&lt;/p&gt;

&lt;p&gt;The MCP server should still validate inputs, enforce authorization, and apply the same security controls as any other API integration.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Composability
&lt;/h3&gt;

&lt;p&gt;AI assistants can combine multiple MCP servers to create workflows across services.&lt;/p&gt;

&lt;p&gt;For example, an assistant could search a pet inventory service, retrieve customer information from another service, and then create an order through the PetstoreAPI MCP server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;MCP bridges AI assistants and APIs. Modern PetstoreAPI implements MCP, allowing Claude Desktop and other AI tools to interact with the pet store through natural language.&lt;/p&gt;

&lt;p&gt;To implement a similar integration:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Identify the API operations the assistant should access.&lt;/li&gt;
&lt;li&gt;Wrap those operations as MCP tools.&lt;/li&gt;
&lt;li&gt;Define accurate input schemas.&lt;/li&gt;
&lt;li&gt;Register the MCP server with an AI client.&lt;/li&gt;
&lt;li&gt;Validate authentication, input handling, and error responses.&lt;/li&gt;
&lt;li&gt;Test both the underlying API and MCP tool calls.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Key takeaways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP connects AI assistants to APIs.&lt;/li&gt;
&lt;li&gt;Tools define what the AI can do.&lt;/li&gt;
&lt;li&gt;Tool schemas describe valid inputs.&lt;/li&gt;
&lt;li&gt;Natural language requests can trigger API calls.&lt;/li&gt;
&lt;li&gt;MCP servers can wrap existing REST APIs.&lt;/li&gt;
&lt;li&gt;Modern PetstoreAPI demonstrates an MCP-based implementation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Which AI assistants support MCP?
&lt;/h3&gt;

&lt;p&gt;Claude Desktop, Cursor, and other Anthropic-powered tools support MCP. Support is growing across AI clients.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is MCP secure?
&lt;/h3&gt;

&lt;p&gt;MCP servers handle authentication, so AI assistants do not need to see the API keys used by the underlying service. You should still validate inputs and enforce authorization in the MCP server and API.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use MCP with existing APIs?
&lt;/h3&gt;

&lt;p&gt;Yes. Build an MCP server that wraps your existing API. Each MCP tool can translate structured tool arguments into requests to your REST or GraphQL endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does MCP replace REST APIs?
&lt;/h3&gt;

&lt;p&gt;No. MCP is an interface for AI assistant access. REST APIs remain useful for direct programmatic access, integrations, and clients that do not use MCP.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I test MCP tools?
&lt;/h3&gt;

&lt;p&gt;Use Apidog to test the underlying APIs and contracts, then connect the MCP server to an MCP-compatible client such as Claude Desktop to test tool discovery and execution.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>WebSocket vs Server-Sent Events: Which Is Better for Real-Time APIs?</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Sat, 29 Aug 2026 13:01:28 +0000</pubDate>
      <link>https://dev.to/preecha/websocket-vs-server-sent-events-which-is-better-for-real-time-apis-15a5</link>
      <guid>https://dev.to/preecha/websocket-vs-server-sent-events-which-is-better-for-real-time-apis-15a5</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use Server-Sent Events (SSE) for one-way server-to-client updates such as notifications, status changes, and live feeds. Use WebSocket for bidirectional communication such as chat, gaming, and live bidding. SSE is simpler and runs over HTTP, while WebSocket provides lower-latency two-way messaging at the cost of additional complexity. Modern PetstoreAPI uses both protocols for different real-time scenarios.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Suppose a pet changes from &lt;code&gt;available&lt;/code&gt; to &lt;code&gt;adopted&lt;/code&gt;. Clients need to receive that update immediately. Should you use WebSocket or Server-Sent Events (SSE)?&lt;/p&gt;

&lt;p&gt;WebSocket is often the default because it supports more communication patterns. However, SSE is usually the better option when the server only needs to push updates. It uses standard HTTP, works with existing HTTP infrastructure, and includes browser-managed reconnection.&lt;/p&gt;

&lt;p&gt;Modern PetstoreAPI uses both protocols:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSE&lt;/strong&gt; for pet status updates and order notifications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket&lt;/strong&gt; for live auction bidding and real-time chat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The right choice depends on how data flows through your application.&lt;/p&gt;

&lt;p&gt;If you are building or testing real-time APIs, Apidog supports both SSE and WebSocket testing. You can test event streams, validate message formats, and simulate reconnection scenarios.&lt;/p&gt;

&lt;p&gt;This guide compares SSE and WebSocket, demonstrates both implementations with Modern PetstoreAPI examples, and explains when to use each protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Server-Sent Events (SSE)?
&lt;/h2&gt;

&lt;p&gt;SSE is an HTTP-based protocol for streaming events from a server to a client.&lt;/p&gt;

&lt;h3&gt;
  
  
  How SSE Works
&lt;/h3&gt;

&lt;p&gt;The client opens a long-lived HTTP connection and listens for events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://petstoreapi.com/v1/pets/notifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;eventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pet update:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;eventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adoption&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Pet adopted:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;petId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server responds with a &lt;code&gt;text/event-stream&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;GET&lt;/span&gt; &lt;span class="nn"&gt;/v1/pets/notifications&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;text/event-stream&lt;/span&gt;

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache

event: adoption
data: {"petId":"019b4132","userId":"user-456"}

event: status-change
data: {"petId":"019b4127","status":"AVAILABLE"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each event ends with a blank line. The &lt;code&gt;event&lt;/code&gt; field identifies the event type, and the &lt;code&gt;data&lt;/code&gt; field contains the payload.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSE Features
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. One-way communication
&lt;/h4&gt;

&lt;p&gt;The server pushes messages to the client. The client cannot send messages through the SSE connection, but it can use regular HTTP requests for client-to-server actions.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Built on HTTP
&lt;/h4&gt;

&lt;p&gt;SSE uses standard HTTP and can work with HTTP proxies, firewalls, and CDNs.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Automatic reconnection
&lt;/h4&gt;

&lt;p&gt;When the connection drops, the browser automatically attempts to reconnect.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Event IDs for resuming
&lt;/h4&gt;

&lt;p&gt;The server can assign IDs to events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;id: 123
event: adoption
data: {"petId":"019b4132"}

id: 124
event: status-change
data: {"petId":"019b4127"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After disconnecting, the client sends the last received ID in the &lt;code&gt;Last-Event-ID&lt;/code&gt; header so the server can resume the stream.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Simple text-based protocol
&lt;/h4&gt;

&lt;p&gt;You can inspect an SSE stream directly with &lt;code&gt;curl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: text/event-stream"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  https://petstoreapi.com/v1/pets/notifications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  SSE Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-way only:&lt;/strong&gt; Client-to-server communication requires separate HTTP requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text-only:&lt;/strong&gt; Binary data must be encoded, such as with base64.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Browser connection limits:&lt;/strong&gt; Browsers typically limit SSE connections per domain to about six.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No protocol-level compression:&lt;/strong&gt; HTTP compression can still be used, but SSE does not provide a WebSocket-style compression mechanism.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Is WebSocket?
&lt;/h2&gt;

&lt;p&gt;WebSocket is a full-duplex protocol that keeps a persistent connection open for communication in both directions.&lt;/p&gt;

&lt;h3&gt;
  
  
  How WebSocket Works
&lt;/h3&gt;

&lt;p&gt;The client and server can send messages at any time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://petstoreapi.com/auctions/019b4132&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Auction update:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connection closed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Add manual reconnection logic when needed.&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server can send messages such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"user-456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;550&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"outbid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"newAmount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;550&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client can send messages such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"petId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"019b4132"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WebSocket Features
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Bidirectional communication
&lt;/h4&gt;

&lt;p&gt;Both the client and server can send messages whenever necessary.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Low latency
&lt;/h4&gt;

&lt;p&gt;After the connection is established, messages do not require a new HTTP request. This makes WebSocket suitable for gaming, chat, and live collaboration.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Binary data support
&lt;/h4&gt;

&lt;p&gt;WebSocket can send binary frames directly, so images, audio, and video do not need base64 encoding.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Custom protocol
&lt;/h4&gt;

&lt;p&gt;Connections use &lt;code&gt;ws://&lt;/code&gt; or secure &lt;code&gt;wss://&lt;/code&gt;. After the initial handshake, communication uses the WebSocket protocol.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Frame-based messages
&lt;/h4&gt;

&lt;p&gt;WebSocket frames allow messages to be transmitted and reassembled independently.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;More complex setup:&lt;/strong&gt; You need a WebSocket server and connection lifecycle management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual reconnection:&lt;/strong&gt; Applications must implement retry and reconnection logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proxy compatibility issues:&lt;/strong&gt; Some corporate proxies block or do not fully support WebSocket traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateful connections:&lt;/strong&gt; The server must track active connections, which can make scaling more involved.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Limited HTTP semantics after the handshake:&lt;/strong&gt; You cannot rely on HTTP caching, status codes, or standard headers for each message.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  SSE vs. WebSocket: Side-by-Side Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;SSE&lt;/th&gt;
&lt;th&gt;WebSocket&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Direction&lt;/td&gt;
&lt;td&gt;Server → client&lt;/td&gt;
&lt;td&gt;Bidirectional&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;HTTP&lt;/td&gt;
&lt;td&gt;WebSocket (&lt;code&gt;ws://&lt;/code&gt; or &lt;code&gt;wss://&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reconnection&lt;/td&gt;
&lt;td&gt;Automatic in browsers&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser support&lt;/td&gt;
&lt;td&gt;All modern browsers&lt;/td&gt;
&lt;td&gt;All modern browsers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proxy-friendly&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Binary data&lt;/td&gt;
&lt;td&gt;No, text only&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scalability&lt;/td&gt;
&lt;td&gt;High for many stateless HTTP patterns&lt;/td&gt;
&lt;td&gt;Medium because connections are stateful&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical use cases&lt;/td&gt;
&lt;td&gt;Notifications and feeds&lt;/td&gt;
&lt;td&gt;Chat, gaming, and collaboration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How Modern PetstoreAPI Uses Both
&lt;/h2&gt;

&lt;p&gt;Modern PetstoreAPI chooses the protocol based on the communication pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use SSE for Pet Updates
&lt;/h3&gt;

&lt;p&gt;Endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://petstoreapi.com/v1/pets/notifications
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A client can subscribe to updates for a specific user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;events&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://petstoreapi.com/v1/pets/notifications?userId=user-456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;adoption&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;showNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;petName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; was adopted!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;status-change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nf"&gt;updatePetStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;petId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A Node.js server can create the stream like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/v1/pets/notifications&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text/event-stream&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache-Control&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keep-alive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;petUpdates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`event: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SSE is a good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pet status changes, such as &lt;code&gt;available&lt;/code&gt; → &lt;code&gt;adopted&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Order notifications, such as placed, shipped, and delivered&lt;/li&gt;
&lt;li&gt;Inventory updates&lt;/li&gt;
&lt;li&gt;Price changes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use WebSocket for Live Auctions
&lt;/h3&gt;

&lt;p&gt;Endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wss://petstoreapi.com/auctions/{auctionId}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client can place bids and process updates over the same connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://petstoreapi.com/auctions/019b4132&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;placeBid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;amount&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;switch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;updateCurrentBid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;outbid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;showOutbidNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;newAmount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;auction-end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nf"&gt;showAuctionResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;winner&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A server can process bids and broadcast them to all auction participants:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auctionId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;auctionId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;auctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;auctionId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;auction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;placeBid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="nx"&gt;auction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WebSocket is a good fit for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live auction bidding&lt;/li&gt;
&lt;li&gt;Real-time support chat&lt;/li&gt;
&lt;li&gt;Collaborative pet care planning&lt;/li&gt;
&lt;li&gt;Live inventory updates during sales&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Testing Real-Time APIs with Apidog
&lt;/h2&gt;

&lt;p&gt;Apidog supports testing both SSE and WebSocket APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test an SSE Endpoint
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create an SSE request:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;   GET https://petstoreapi.com/v1/pets/notifications
   Accept: text/event-stream
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Validate the event stream:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Check event types.&lt;/li&gt;
&lt;li&gt;Validate JSON payloads.&lt;/li&gt;
&lt;li&gt;Verify event IDs.&lt;/li&gt;
&lt;li&gt;Confirm that events arrive in the expected order.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Test failure and recovery scenarios:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Drop the connection.&lt;/li&gt;
&lt;li&gt;Restart the server.&lt;/li&gt;
&lt;li&gt;Resume from the last event ID.&lt;/li&gt;
&lt;li&gt;Verify reconnection behavior.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test a WebSocket Connection
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a connection:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   wss://petstoreapi.com/auctions/019b4132
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Send test messages:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bid"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"watch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"petId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"019b4132"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Validate responses:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Check message formats.&lt;/li&gt;
&lt;li&gt;Test client-to-server and server-to-client flows.&lt;/li&gt;
&lt;li&gt;Verify connection handling.&lt;/li&gt;
&lt;li&gt;Test invalid messages and error responses.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Test operational scenarios:&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Multiple concurrent connections&lt;/li&gt;
&lt;li&gt;Message ordering&lt;/li&gt;
&lt;li&gt;Connection timeouts&lt;/li&gt;
&lt;li&gt;Reconnection logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use SSE
&lt;/h2&gt;

&lt;p&gt;Choose SSE when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The server is the primary sender.&lt;/li&gt;
&lt;li&gt;You want to use standard HTTP infrastructure.&lt;/li&gt;
&lt;li&gt;Browser-managed reconnection is useful.&lt;/li&gt;
&lt;li&gt;The connection must work through HTTP proxies and firewalls.&lt;/li&gt;
&lt;li&gt;You are delivering notifications, status updates, or feeds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pet adoption notifications&lt;/li&gt;
&lt;li&gt;Order status updates&lt;/li&gt;
&lt;li&gt;Inventory changes&lt;/li&gt;
&lt;li&gt;Price alerts&lt;/li&gt;
&lt;li&gt;News feeds&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When to Use WebSocket
&lt;/h2&gt;

&lt;p&gt;Choose WebSocket when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both client and server send messages frequently.&lt;/li&gt;
&lt;li&gt;Low latency is critical.&lt;/li&gt;
&lt;li&gt;The application needs binary frames.&lt;/li&gt;
&lt;li&gt;You need a custom message protocol.&lt;/li&gt;
&lt;li&gt;The application handles a high message frequency, such as hundreds of messages per second.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live auction bidding&lt;/li&gt;
&lt;li&gt;Real-time chat&lt;/li&gt;
&lt;li&gt;Multiplayer games&lt;/li&gt;
&lt;li&gt;Collaborative editing&lt;/li&gt;
&lt;li&gt;Live video streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Do Not Choose WebSocket Just Because It Seems More Advanced
&lt;/h3&gt;

&lt;p&gt;Avoid adding WebSocket complexity when your application only needs server-to-client updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;“It’s more advanced.”&lt;/strong&gt; Extra complexity does not provide value if you do not need bidirectional messaging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“Everyone uses it.”&lt;/strong&gt; SSE may be a better fit for simple event streams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“It’s faster.”&lt;/strong&gt; SSE is fast enough for many notification and status-update scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;“It’s bidirectional.”&lt;/strong&gt; First confirm that the client actually needs to send messages through the persistent connection.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;SSE and WebSocket both support real-time communication, but they solve different problems.&lt;/p&gt;

&lt;p&gt;SSE is a practical choice for one-way server-to-client updates because it is simple, HTTP-compatible, and supports automatic browser reconnection. WebSocket is better for bidirectional, low-latency communication such as live auctions, chat, and gaming.&lt;/p&gt;

&lt;p&gt;Modern PetstoreAPI uses SSE for notifications and status updates, and WebSocket for live auctions and chat. Choose the protocol based on your communication pattern—not on which protocol appears more powerful.&lt;/p&gt;

&lt;p&gt;Test your real-time APIs with Apidog to verify event streams, message formats, reconnection behavior, and failure scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can SSE work through corporate firewalls?
&lt;/h3&gt;

&lt;p&gt;Yes. SSE uses standard HTTP, so it generally works through HTTP proxies and firewalls. WebSocket uses a custom protocol that some proxies block.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is WebSocket faster than SSE?
&lt;/h3&gt;

&lt;p&gt;WebSocket can have slightly lower latency because messages do not include HTTP overhead after the handshake. For many applications, however, the difference is negligible, and SSE is fast enough for notifications, feeds, and status updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you handle SSE reconnection?
&lt;/h3&gt;

&lt;p&gt;Browsers handle reconnection automatically. The server should send event IDs so the client can reconnect with the &lt;code&gt;Last-Event-ID&lt;/code&gt; header and resume from the last received event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can you use SSE with mobile apps?
&lt;/h3&gt;

&lt;p&gt;Yes. iOS and Android applications can consume SSE through native HTTP clients or libraries. SSE works anywhere HTTP works.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the maximum SSE connection time?
&lt;/h3&gt;

&lt;p&gt;There is no protocol-defined maximum. An SSE connection can remain open indefinitely, although proxies or load balancers may impose timeouts, often around 30–60 seconds. The browser can reconnect when the connection closes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can WebSocket send binary data?
&lt;/h3&gt;

&lt;p&gt;Yes. WebSocket supports both text and binary frames, allowing applications to send images, audio, or other binary data without base64 encoding.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many SSE connections can a browser have?
&lt;/h3&gt;

&lt;p&gt;Browsers typically limit SSE connections per domain to about six. This is rarely a problem because most applications only need one or two SSE connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do you need a special server for SSE?
&lt;/h3&gt;

&lt;p&gt;No. Any HTTP server can handle SSE. Set &lt;code&gt;Content-Type: text/event-stream&lt;/code&gt;, keep the response open, and write events using the SSE format.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>When Should You Use MQTT Instead of HTTP for APIs?</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Sat, 29 Aug 2026 02:01:48 +0000</pubDate>
      <link>https://dev.to/preecha/when-should-you-use-mqtt-instead-of-http-for-apis-2d46</link>
      <guid>https://dev.to/preecha/when-should-you-use-mqtt-instead-of-http-for-apis-2d46</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use MQTT for IoT devices with limited battery, unreliable networks, or pub-sub messaging patterns. Use HTTP for standard web and mobile APIs. MQTT uses 2-byte headers compared with HTTP’s 100+ bytes, making it suitable for constrained devices. Modern PetstoreAPI uses MQTT for pet tracking collars and smart feeders.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Imagine a pet tracking collar that sends a location update every five minutes. It runs on a coin-cell battery designed to last six months.&lt;/p&gt;

&lt;p&gt;With HTTP, the battery might last only two weeks. With MQTT, it can last the full six months.&lt;/p&gt;

&lt;p&gt;HTTP is the standard choice for web and mobile APIs, but it was designed for general-purpose request-response communication. MQTT (Message Queuing Telemetry Transport) was designed for constrained devices operating with limited bandwidth, battery power, and unreliable networks.&lt;/p&gt;

&lt;p&gt;Modern PetstoreAPI uses both protocols:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP for web and mobile applications&lt;/li&gt;
&lt;li&gt;MQTT for IoT devices such as pet tracking collars, smart feeders, and health monitors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re building or testing IoT APIs, Apidog supports MQTT testing alongside HTTP. You can test pub-sub patterns, validate message formats, and simulate network failures.&lt;/p&gt;

&lt;p&gt;In this guide, you’ll learn when MQTT is a better fit than HTTP, how Modern PetstoreAPI uses both protocols, and how to test each approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is MQTT?
&lt;/h2&gt;

&lt;p&gt;MQTT is a lightweight publish-subscribe messaging protocol designed for IoT applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  How MQTT Works
&lt;/h3&gt;

&lt;p&gt;MQTT clients publish messages to topics. Other clients subscribe to those topics. An MQTT broker routes messages between publishers and subscribers.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Publisher: Pet collar
Topic: pets/019b4132/location
Payload: {"lat":37.7749,"lng":-122.4194,"battery":85}

Subscriber: Mobile app
Subscription: pets/019b4132/location
Receives: {"lat":37.7749,"lng":-122.4194,"battery":85}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The collar does not need to know which applications consume the message. It only publishes to the topic. Any authorized subscriber can receive updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Core MQTT Features
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Small headers&lt;/strong&gt; — MQTT headers can be as small as 2 bytes, compared with roughly 100–500 bytes for typical HTTP requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent connections&lt;/strong&gt; — Clients can keep a connection open instead of creating a new connection for every message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality of Service (QoS)&lt;/strong&gt; — QoS 0, 1, and 2 provide different delivery guarantees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Last Will messages&lt;/strong&gt; — A broker can publish a message when a client disconnects unexpectedly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retained messages&lt;/strong&gt; — A broker can store the latest message on a topic and deliver it to new subscribers.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  MQTT vs. HTTP
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;MQTT&lt;/th&gt;
&lt;th&gt;HTTP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Header size&lt;/td&gt;
&lt;td&gt;As small as 2 bytes&lt;/td&gt;
&lt;td&gt;Typically 100–500 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Communication pattern&lt;/td&gt;
&lt;td&gt;Publish-subscribe&lt;/td&gt;
&lt;td&gt;Request-response&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Connection&lt;/td&gt;
&lt;td&gt;Persistent&lt;/td&gt;
&lt;td&gt;Per request, unless reused&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bandwidth usage&lt;/td&gt;
&lt;td&gt;Very low&lt;/td&gt;
&lt;td&gt;Higher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Battery impact&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Significant for constrained devices&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser support&lt;/td&gt;
&lt;td&gt;Through WebSocket&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Bandwidth Example
&lt;/h3&gt;

&lt;p&gt;Assume a device sends 1,000 location updates per day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP: approximately 420 KB per day, or 12.6 MB per month&lt;/li&gt;
&lt;li&gt;MQTT: approximately 52 KB per day, or 1.56 MB per month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example, MQTT uses approximately eight times less bandwidth.&lt;/p&gt;

&lt;p&gt;Actual usage depends on payload size, connection behavior, TLS settings, and protocol overhead. The example illustrates why MQTT is useful for bandwidth-constrained devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  When MQTT Is the Better Choice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Battery-Powered IoT Devices
&lt;/h3&gt;

&lt;p&gt;For a pet tracking collar:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MQTT: six months of battery life&lt;/li&gt;
&lt;li&gt;HTTP: two weeks of battery life&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MQTT helps reduce radio usage through persistent connections and smaller protocol overhead.&lt;/p&gt;

&lt;p&gt;Use MQTT when the device:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Runs on a small battery&lt;/li&gt;
&lt;li&gt;Sends frequent updates&lt;/li&gt;
&lt;li&gt;Has limited processing power&lt;/li&gt;
&lt;li&gt;Operates over a metered or low-bandwidth connection&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Unreliable Networks
&lt;/h3&gt;

&lt;p&gt;Cellular IoT devices may frequently lose connectivity. MQTT provides features that help applications recover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;QoS for delivery guarantees&lt;/li&gt;
&lt;li&gt;Automatic reconnection in client libraries&lt;/li&gt;
&lt;li&gt;Session persistence&lt;/li&gt;
&lt;li&gt;Last Will messages for detecting unexpected disconnects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical implementation should define what happens when a device disconnects and how it resynchronizes after reconnecting.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Many-to-Many Communication
&lt;/h3&gt;

&lt;p&gt;MQTT topics make it easy for multiple devices and applications to exchange messages.&lt;/p&gt;

&lt;p&gt;For a smart pet feeder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feeder 1 publishes to pets/019b4132/feeding
Feeder 2 publishes to pets/019b4127/feeding

App 1 subscribes to pets/+/feeding
App 2 subscribes to pets/019b4132/feeding
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;+&lt;/code&gt; wildcard matches one topic level, so &lt;code&gt;pets/+/feeding&lt;/code&gt; receives feeding events for all pets.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Real-Time Sensor Data
&lt;/h3&gt;

&lt;p&gt;A pet health monitor might send an update every second:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: pets/019b4132/health
QoS: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MQTT is useful for this workload because it avoids repeated request setup, minimizes latency, and supports high-frequency messages over a persistent connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  When HTTP Is the Better Choice
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Standard Web and Mobile Applications
&lt;/h3&gt;

&lt;p&gt;HTTP is usually the simplest option for user-facing applications because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every major language has HTTP libraries&lt;/li&gt;
&lt;li&gt;Browsers support it natively&lt;/li&gt;
&lt;li&gt;Proxies and firewalls commonly allow it&lt;/li&gt;
&lt;li&gt;HTTP APIs are familiar to most developers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Request-Response Operations
&lt;/h3&gt;

&lt;p&gt;Use HTTP when a client needs to request a specific resource and receive a direct response.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET /pets/019b4132
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;200 OK
Content-Type: application/json

{
  "name": "Fluffy",
  "species": "CAT"
}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This interaction is naturally represented by HTTP. Using MQTT would require defining request and response topics and correlating messages manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Caching
&lt;/h3&gt;

&lt;p&gt;HTTP provides established caching mechanisms, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Browser caching&lt;/li&gt;
&lt;li&gt;CDN caching&lt;/li&gt;
&lt;li&gt;Proxy caching&lt;/li&gt;
&lt;li&gt;Cache-Control headers&lt;/li&gt;
&lt;li&gt;Conditional requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MQTT does not provide HTTP-style caching. Although retained messages can provide the latest value on a topic, they are not a replacement for general-purpose HTTP caching.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. RESTful APIs
&lt;/h3&gt;

&lt;p&gt;HTTP provides standard methods, status codes, and semantics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Methods: &lt;code&gt;GET&lt;/code&gt;, &lt;code&gt;POST&lt;/code&gt;, &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Status codes: &lt;code&gt;200 OK&lt;/code&gt;, &lt;code&gt;201 Created&lt;/code&gt;, &lt;code&gt;404 Not Found&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Standard request and response handling&lt;/li&gt;
&lt;li&gt;Established error-handling conventions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Modern PetstoreAPI Uses MQTT
&lt;/h2&gt;

&lt;p&gt;Modern PetstoreAPI uses HTTP for user-facing APIs and MQTT for IoT device communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pet Tracking Collars
&lt;/h3&gt;

&lt;p&gt;A collar publishes location updates to a pet-specific topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: pets/019b4132/location
QoS: 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;37.7749&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lng"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;-122.4194&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"battery"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;85&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-13T10:30:00Z"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A mobile application subscribes to the topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mqtt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mqtt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;mqtt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mqtts://mqtt.petstoreapi.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pets/019b4132/location&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Subscription failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

  &lt;span class="nf"&gt;updateMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The example uses QoS 1, which provides at-least-once delivery. Consumers should therefore be prepared to handle duplicate messages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Smart Feeders
&lt;/h3&gt;

&lt;p&gt;A feeder subscribes to its feeding schedule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: pets/019b4132/feeding-schedule
Retained: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"times"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"08:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"18:00"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The retained message allows a feeder to receive the latest schedule when it subscribes.&lt;/p&gt;

&lt;p&gt;The feeder publishes feeding events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: pets/019b4132/feeding-events
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-03-13T08:00:15Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dispensed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Health Monitors
&lt;/h3&gt;

&lt;p&gt;A health monitor publishes high-frequency vital updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Topic: pets/019b4132/health
QoS: 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"heartRate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"temperature"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;38.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"activity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resting"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;QoS 0 is suitable when occasional message loss is acceptable and the device will publish another reading shortly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing MQTT with Apidog
&lt;/h2&gt;

&lt;p&gt;Apidog supports MQTT testing alongside HTTP and other protocols.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test an MQTT Pub-Sub Flow
&lt;/h3&gt;

&lt;p&gt;Use the following workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect to the MQTT broker.&lt;/li&gt;
&lt;li&gt;Subscribe to the topic used by the application.&lt;/li&gt;
&lt;li&gt;Publish a test message from a separate client or request.&lt;/li&gt;
&lt;li&gt;Validate the received topic and payload.&lt;/li&gt;
&lt;li&gt;Test the behavior for QoS 0, 1, and 2.&lt;/li&gt;
&lt;li&gt;Confirm that consumers handle duplicate or delayed messages where applicable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the pet location example, publish a message to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pets/019b4132/location
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then verify that the mobile application receives and parses the expected payload.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simulate Network Failures
&lt;/h3&gt;

&lt;p&gt;Test how devices and consumers behave when connectivity changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disconnect and reconnect the client&lt;/li&gt;
&lt;li&gt;Test automatic reconnection&lt;/li&gt;
&lt;li&gt;Verify QoS 1 and QoS 2 delivery behavior&lt;/li&gt;
&lt;li&gt;Check Last Will messages&lt;/li&gt;
&lt;li&gt;Validate session persistence&lt;/li&gt;
&lt;li&gt;Confirm that retained messages are delivered to new subscribers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These tests are especially important for cellular devices that can lose connectivity without warning.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compare MQTT with HTTP
&lt;/h3&gt;

&lt;p&gt;Implement the same operation through both protocols and compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bandwidth usage&lt;/li&gt;
&lt;li&gt;Message latency&lt;/li&gt;
&lt;li&gt;Battery or connection overhead&lt;/li&gt;
&lt;li&gt;Delivery behavior&lt;/li&gt;
&lt;li&gt;Data consistency&lt;/li&gt;
&lt;li&gt;Recovery after network failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives you measurable criteria for choosing a protocol instead of choosing based only on familiarity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;MQTT and HTTP solve different problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use MQTT for constrained IoT devices, unreliable networks, real-time sensor data, and pub-sub communication.&lt;/li&gt;
&lt;li&gt;Use HTTP for standard web and mobile APIs, request-response operations, caching, and RESTful resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern PetstoreAPI uses both protocols: HTTP for user-facing APIs and MQTT for IoT devices. The right choice depends on your device constraints, communication pattern, reliability requirements, and caching needs—not on which protocol is universally “better.”&lt;/p&gt;

&lt;p&gt;Test both protocols with Apidog to determine which implementation best fits your use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can MQTT Work Over HTTP?
&lt;/h3&gt;

&lt;p&gt;MQTT can run over WebSocket, which works over HTTP. This can help with firewall traversal and browser compatibility, but it adds transport overhead compared with a direct MQTT connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Are MQTT QoS Levels?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;QoS 0: At most once&lt;/strong&gt; — The message is delivered without acknowledgment. It may be lost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QoS 1: At least once&lt;/strong&gt; — The message is acknowledged, but it may be delivered more than once.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;QoS 2: Exactly once&lt;/strong&gt; — The protocol provides the strongest delivery guarantee and prevents duplicate delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose the lowest QoS level that meets your application’s requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is MQTT Secure?
&lt;/h3&gt;

&lt;p&gt;MQTT supports TLS encryption through MQTTS and username/password authentication. Modern PetstoreAPI uses MQTTS for its IoT devices.&lt;/p&gt;

&lt;p&gt;In production, use encrypted connections, authenticate clients, and restrict which topics each client can publish or subscribe to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can Browsers Use MQTT?
&lt;/h3&gt;

&lt;p&gt;Browsers can use MQTT over WebSocket. Libraries such as MQTT.js support browser environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Does MQTT Compare with WebSocket?
&lt;/h3&gt;

&lt;p&gt;MQTT is a messaging protocol that can run over WebSocket. WebSocket is a transport layer that provides a persistent, bidirectional connection.&lt;/p&gt;

&lt;p&gt;MQTT adds IoT-specific messaging features such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pub-sub topics&lt;/li&gt;
&lt;li&gt;QoS levels&lt;/li&gt;
&lt;li&gt;Retained messages&lt;/li&gt;
&lt;li&gt;Last Will messages&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use WebSocket directly when you need a custom bidirectional protocol. Use MQTT when you need standardized pub-sub messaging and MQTT delivery features.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Socket.IO vs Native WebSocket: Which Should You Use?</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Sat, 29 Aug 2026 01:01:20 +0000</pubDate>
      <link>https://dev.to/preecha/socketio-vs-native-websocket-which-should-you-use-2b95</link>
      <guid>https://dev.to/preecha/socketio-vs-native-websocket-which-should-you-use-2b95</guid>
      <description>&lt;h1&gt;
  
  
  Native WebSocket vs. Socket.IO: Which Should You Use?
&lt;/h1&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Use Native WebSocket for simple, low-latency communication in modern browsers. Use Socket.IO when you need automatic reconnection, fallback transports, rooms, or namespaces. Socket.IO adds 200KB+ of overhead but handles more connection edge cases. Modern PetstoreAPI uses Native WebSocket for auctions and Socket.IO for support chat.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Real-time features require bidirectional communication between the client and server. The right protocol depends on how much connection management your application needs.&lt;/p&gt;

&lt;p&gt;Native WebSocket is built into modern browsers and has minimal overhead. Socket.IO adds features such as reconnection, fallback transports, rooms, namespaces, and acknowledgments, but increases bundle size by 200KB+.&lt;/p&gt;

&lt;p&gt;Modern PetstoreAPI uses both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Native WebSocket&lt;/strong&gt; for live pet auctions, where latency matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Socket.IO&lt;/strong&gt; for customer support chat, where reconnection and rooms are more valuable.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re testing real-time APIs, Apidog supports both Native WebSocket and Socket.IO testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Native WebSocket
&lt;/h2&gt;

&lt;p&gt;Native WebSocket is the browser standard for bidirectional communication. It uses a straightforward event-based API and does not require a client library.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://petstoreapi.com/auctions/019b4132&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Received:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onerror&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebSocket error:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connection closed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No dependencies:&lt;/strong&gt; WebSocket is built into modern browsers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Low overhead:&lt;/strong&gt; There is no additional client protocol layer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simple API:&lt;/strong&gt; The connection lifecycle is easy to understand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Small bundle size:&lt;/strong&gt; The browser provides the implementation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No automatic reconnection:&lt;/strong&gt; You must implement retry logic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No fallback transport:&lt;/strong&gt; If WebSocket cannot connect, the client does not automatically switch transports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No built-in rooms or namespaces:&lt;/strong&gt; You must implement this behavior yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Manual connection health:&lt;/strong&gt; Your application may need ping/pong or heartbeat handling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a basic reconnect strategy can be implemented around the connection factory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://petstoreapi.com/auctions/019b4132&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onopen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Received:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onclose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Connection closed; retrying...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In production, add limits and backoff to avoid retrying indefinitely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Socket.IO
&lt;/h2&gt;

&lt;p&gt;Socket.IO is a library that adds connection-management and messaging features around real-time communication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic usage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;socket.io-client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://petstoreapi.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;join-room&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;support-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Received:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disconnect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Disconnected; Socket.IO will attempt to reconnect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key features
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Automatic reconnection
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://petstoreapi.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;reconnection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reconnectionDelay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;reconnectionAttempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Fallback transports
&lt;/h4&gt;

&lt;p&gt;If WebSocket fails, Socket.IO can try other transports, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WebSocket&lt;/li&gt;
&lt;li&gt;HTTP long-polling&lt;/li&gt;
&lt;li&gt;HTTP streaming&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  3. Rooms and namespaces
&lt;/h4&gt;

&lt;p&gt;Rooms let the server group connections. Namespaces separate communication channels.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Server&lt;/span&gt;
&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connection&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;support-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;support-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-joined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Client&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Acknowledgments
&lt;/h4&gt;

&lt;p&gt;Acknowledgments let the server confirm that an event was received or processed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server acknowledged:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Binary support
&lt;/h4&gt;

&lt;p&gt;Socket.IO can send binary data such as buffers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Larger bundle:&lt;/strong&gt; The minified client adds 200KB+ of overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server dependency:&lt;/strong&gt; The server must support Socket.IO.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More concepts:&lt;/strong&gt; You need to understand events, rooms, namespaces, and acknowledgments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol overhead:&lt;/strong&gt; Socket.IO adds an additional protocol layer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Native WebSocket vs. Socket.IO
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Native WebSocket&lt;/th&gt;
&lt;th&gt;Socket.IO&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Bundle size&lt;/td&gt;
&lt;td&gt;0 KB&lt;/td&gt;
&lt;td&gt;200+ KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automatic reconnect&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fallback transport&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, including long-polling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rooms&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Namespaces&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Acknowledgments&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Binary data&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser support&lt;/td&gt;
&lt;td&gt;Modern browsers&lt;/td&gt;
&lt;td&gt;Broad support through fallback&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server&lt;/td&gt;
&lt;td&gt;Any WebSocket server&lt;/td&gt;
&lt;td&gt;Socket.IO server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;More feature-rich&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How Modern PetstoreAPI Uses Both
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Native WebSocket for auctions
&lt;/h3&gt;

&lt;p&gt;Live auctions need low latency and use a simple bidding protocol:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;wss://petstoreapi.com/auctions/019b4132&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;updateBidDisplay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sold&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;showSoldNotification&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;winnerId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;placeBid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;amount&lt;/span&gt;
  &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;placeBid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Native WebSocket is a good fit because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performance is critical.&lt;/li&gt;
&lt;li&gt;The target audience uses modern browsers.&lt;/li&gt;
&lt;li&gt;The message protocol is simple.&lt;/li&gt;
&lt;li&gt;The feature does not require rooms.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Socket.IO for support chat
&lt;/h3&gt;

&lt;p&gt;Customer support chat prioritizes reliability and connection management:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;io&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://petstoreapi.com/chat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;join-support&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;displayMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;agent-typing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;showTypingIndicator&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;I need help with my order&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-456&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Socket.IO is a good fit because it provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic reconnection for users on mobile networks.&lt;/li&gt;
&lt;li&gt;Rooms for multiple support sessions.&lt;/li&gt;
&lt;li&gt;Fallback transports for networks where WebSocket is unavailable.&lt;/li&gt;
&lt;li&gt;Acknowledgments for message delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the Modern PetstoreAPI WebSocket docs and Socket.IO docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with Apidog
&lt;/h2&gt;

&lt;p&gt;Apidog supports testing both protocols.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test a Native WebSocket connection
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a WebSocket request.&lt;/li&gt;
&lt;li&gt;Connect to &lt;code&gt;wss://petstoreapi.com/auctions/019b4132&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Send test messages such as a bid event.&lt;/li&gt;
&lt;li&gt;Validate the server responses.&lt;/li&gt;
&lt;li&gt;Test connection-close and reconnect behavior if your client implements it.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Test a Socket.IO connection
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Create a Socket.IO connection.&lt;/li&gt;
&lt;li&gt;Test events and acknowledgments.&lt;/li&gt;
&lt;li&gt;Validate room behavior.&lt;/li&gt;
&lt;li&gt;Test reconnection scenarios.&lt;/li&gt;
&lt;li&gt;Verify fallback behavior when WebSocket is unavailable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  When to Use Each
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use Native WebSocket when
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You are building for modern browsers only.&lt;/li&gt;
&lt;li&gt;Performance is critical.&lt;/li&gt;
&lt;li&gt;You need simple bidirectional messaging.&lt;/li&gt;
&lt;li&gt;You want minimal bundle size.&lt;/li&gt;
&lt;li&gt;You do not need automatic reconnection.&lt;/li&gt;
&lt;li&gt;You can implement rooms and health checks yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typical examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live auctions&lt;/li&gt;
&lt;li&gt;Real-time dashboards&lt;/li&gt;
&lt;li&gt;Gaming with manual reconnect handling&lt;/li&gt;
&lt;li&gt;Stock tickers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use Socket.IO when
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You need automatic reconnection.&lt;/li&gt;
&lt;li&gt;You need support for older browsers.&lt;/li&gt;
&lt;li&gt;Users may connect through corporate networks.&lt;/li&gt;
&lt;li&gt;You need rooms or namespaces.&lt;/li&gt;
&lt;li&gt;You want event acknowledgments.&lt;/li&gt;
&lt;li&gt;Your users may have unreliable mobile connections.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typical examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chat applications&lt;/li&gt;
&lt;li&gt;Collaborative editing&lt;/li&gt;
&lt;li&gt;Customer support&lt;/li&gt;
&lt;li&gt;Notifications with delivery confirmation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Native WebSocket is faster and simpler, while Socket.IO is more feature-rich and heavier. Choose based on the connection behavior and messaging features your application requires.&lt;/p&gt;

&lt;p&gt;Modern PetstoreAPI uses both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native WebSocket where performance matters.&lt;/li&gt;
&lt;li&gt;Socket.IO where reliability and built-in features matter.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I use Socket.IO with Native WebSocket clients?
&lt;/h3&gt;

&lt;p&gt;No. Socket.IO uses a custom protocol. A Socket.IO server requires a Socket.IO client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Socket.IO work through corporate firewalls?
&lt;/h3&gt;

&lt;p&gt;It can. If WebSocket is blocked, Socket.IO can fall back to HTTP long-polling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Socket.IO slower than Native WebSocket?
&lt;/h3&gt;

&lt;p&gt;Slightly. Socket.IO adds protocol overhead, but the difference is negligible for most applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I migrate from Socket.IO to Native WebSocket?
&lt;/h3&gt;

&lt;p&gt;Yes, but you will need to implement reconnection, rooms, namespaces, acknowledgments, and other required features yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Native WebSocket support rooms?
&lt;/h3&gt;

&lt;p&gt;No. You must implement room logic on the server and track which connections belong to each room.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What is Tokenization? The Ultimate Guide to API Security</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Fri, 28 Aug 2026 14:01:24 +0000</pubDate>
      <link>https://dev.to/preecha/what-is-tokenization-the-ultimate-guide-to-api-security-1epb</link>
      <guid>https://dev.to/preecha/what-is-tokenization-the-ultimate-guide-to-api-security-1epb</guid>
      <description>&lt;p&gt;Tokenization replaces sensitive data with non-sensitive placeholders called tokens. A token may preserve the original value’s format or length, but it has no useful value by itself. In API security, tokenization lets an application accept payment details, medical records, or personal information while minimizing how often the original data is stored or processed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;A typical tokenization workflow has four controlled stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Capture the data:&lt;/strong&gt; Sensitive information enters the system through a secured API request.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate a token:&lt;/strong&gt; A tokenization service creates an opaque, random token that does not reveal the original value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Store the mapping:&lt;/strong&gt; The original value is stored in an isolated token vault. The vault maps the token to the original data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use the token:&lt;/strong&gt; Internal services and databases use the token instead of the sensitive value for subsequent operations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A simplified request flow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  |  POST /payment-methods
  |  { "cardNumber": "..." }
  v
Tokenization service
  |
  |-- Stores the card number in the token vault
  |-- Returns an opaque token
  v
Application
  |
  |  Stores and uses:
  |  { "paymentToken": "tok_..." }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The token should not contain the original value, a reversible encoding, or predictable information. Access to the token vault must be restricted with authentication, authorization, audit logging, and network controls.&lt;/p&gt;

&lt;p&gt;Tokenization reduces the amount of sensitive data exposed to application services and databases. It can also reduce the systems that directly handle regulated data, although the exact compliance impact depends on the implementation and applicable requirements such as PCI DSS or GDPR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tokenization vs. Encryption: Which Offers Better API Security?
&lt;/h2&gt;

&lt;p&gt;Tokenization and encryption protect data in different ways. Choosing between them depends on where the data is used, whether it must be recovered, and how the keys or token mappings will be managed.&lt;/p&gt;

&lt;h3&gt;
  
  
  How encryption works
&lt;/h3&gt;

&lt;p&gt;Encryption transforms plaintext into ciphertext using an algorithm and a cryptographic key. A service with the correct key can decrypt the ciphertext and recover the original value.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Plaintext  -&amp;gt; Encrypt(key)   -&amp;gt; Ciphertext
Ciphertext -&amp;gt; Decrypt(key)   -&amp;gt; Plaintext
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Encryption is commonly used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data in transit, such as HTTPS and TLS&lt;/li&gt;
&lt;li&gt;Backups and files&lt;/li&gt;
&lt;li&gt;Database fields&lt;/li&gt;
&lt;li&gt;Messages and stored documents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The main security concern is key management. If an attacker obtains both the encrypted data and the decryption key, the data may be exposed.&lt;/p&gt;

&lt;h3&gt;
  
  
  How tokenization works
&lt;/h3&gt;

&lt;p&gt;Tokenization replaces the sensitive value with an opaque reference. The token has no mathematical relationship to the original value, so it is not decrypted. Instead, an authorized service looks up the value in the token vault.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sensitive value -&amp;gt; Token vault lookup -&amp;gt; Opaque token
Opaque token    -&amp;gt; Authorized lookup  -&amp;gt; Sensitive value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application may store and pass a token like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"customerId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cus_12345"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"paymentToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tok_7f31c8..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Only the tokenization service should be able to resolve &lt;code&gt;paymentToken&lt;/code&gt; to the original data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.akamai.com%2Fsite%2Fen%2Fimages%2Fpromo%2F2024%2Fhow-does-an-api-token-work.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.akamai.com%2Fsite%2Fen%2Fimages%2Fpromo%2F2024%2Fhow-does-an-api-token-work.png" alt="Illustration of how an API token works" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Side-by-side comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Tokenization&lt;/th&gt;
&lt;th&gt;Encryption&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Reversibility&lt;/td&gt;
&lt;td&gt;Requires access to the token vault&lt;/td&gt;
&lt;td&gt;Requires the correct decryption key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data relationship&lt;/td&gt;
&lt;td&gt;Opaque value with no mathematical relationship to the original&lt;/td&gt;
&lt;td&gt;Mathematically transformed ciphertext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Key or mapping management&lt;/td&gt;
&lt;td&gt;Protect the token vault and its mappings&lt;/td&gt;
&lt;td&gt;Protect encryption keys and ciphertext&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compliance scope&lt;/td&gt;
&lt;td&gt;Can reduce the systems that handle sensitive data, depending on implementation&lt;/td&gt;
&lt;td&gt;Encrypted data may still remain in scope for applicable requirements&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;Often efficient for reference-based transactions&lt;/td&gt;
&lt;td&gt;Processing cost depends on the algorithm, payload, and implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common use cases&lt;/td&gt;
&lt;td&gt;Payment references, API identifiers, and database fields&lt;/td&gt;
&lt;td&gt;Files, backups, messages, and data in transit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Tokenization and encryption are not mutually exclusive. A practical design often uses both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use TLS to protect API requests in transit.&lt;/li&gt;
&lt;li&gt;Use tokenization to keep raw payment or personal data out of general application systems.&lt;/li&gt;
&lt;li&gt;Encrypt the token vault and its backups.&lt;/li&gt;
&lt;li&gt;Use a dedicated key-management system for encryption keys.&lt;/li&gt;
&lt;li&gt;Enforce authorization before resolving a token.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, an API should usually accept sensitive data only at a narrowly scoped endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /v1/payment-methods
Authorization: Bearer &amp;lt;access-token&amp;gt;
Content-Type: application/json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cardNumber"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"4111111111111111"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expirationMonth"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expirationYear"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2028&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After tokenization, the application should use the returned reference:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"paymentToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tok_7f31c8..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not log the original request body, store it in general-purpose databases, or include it in analytics events.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tokenization Use Cases, Benefits, and Examples
&lt;/h2&gt;

&lt;p&gt;Tokenization is useful when an application needs to reference sensitive data repeatedly without exposing the original value to every service in the workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Retail and e-commerce
&lt;/h3&gt;

&lt;p&gt;An online store can send card details to a payment or tokenization service and store only the resulting payment token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user_2048"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"paymentToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tok_7f31c8..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lastFour"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1111"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The token can be used for future charges, while the raw card number remains outside the merchant’s main application database. The merchant should still verify the provider’s token lifecycle, authorization model, and compliance responsibilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Healthcare
&lt;/h3&gt;

&lt;p&gt;Healthcare systems can tokenize patient identifiers, insurance references, or medical record numbers before sharing them with internal services or external integrations. Services can coordinate around the token while access to the original value remains limited to authorized components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Internal APIs and microservices
&lt;/h3&gt;

&lt;p&gt;Tokenization can reduce the number of services that process sensitive fields. For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An ingestion service receives a sensitive identifier.&lt;/li&gt;
&lt;li&gt;A tokenization service replaces it with an opaque token.&lt;/li&gt;
&lt;li&gt;Downstream services use the token for correlation and processing.&lt;/li&gt;
&lt;li&gt;Only an authorized service can resolve the token when necessary.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Key tokenization benefits
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduced exposure:&lt;/strong&gt; Fewer systems need to store or process raw sensitive data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Simpler data handling:&lt;/strong&gt; Services can pass references instead of sensitive values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Potentially reduced compliance scope:&lt;/strong&gt; The systems that never access raw data may be outside parts of the applicable compliance boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatible integrations:&lt;/strong&gt; Format-preserving tokens can help systems that expect a particular field shape, but the token format must be designed carefully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safer testing:&lt;/strong&gt; Non-production environments can use tokens or synthetic values instead of copied production data.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementation checklist
&lt;/h3&gt;

&lt;p&gt;When adding tokenization to an API, address the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Define which fields require tokenization.&lt;/li&gt;
&lt;li&gt;Choose where tokenization occurs: at the edge, in a dedicated service, or through a third-party provider.&lt;/li&gt;
&lt;li&gt;Keep the token vault isolated from general application storage.&lt;/li&gt;
&lt;li&gt;Use unpredictable tokens with sufficient entropy.&lt;/li&gt;
&lt;li&gt;Authenticate and authorize token creation and resolution separately.&lt;/li&gt;
&lt;li&gt;Return only the minimum data needed by the caller.&lt;/li&gt;
&lt;li&gt;Prevent raw values from appearing in logs, traces, error messages, and analytics.&lt;/li&gt;
&lt;li&gt;Define token expiration, revocation, and rotation behavior.&lt;/li&gt;
&lt;li&gt;Monitor token-resolution events and alert on unusual access.&lt;/li&gt;
&lt;li&gt;Test failure cases, including vault timeouts and invalid tokens.&lt;/li&gt;
&lt;li&gt;Use synthetic data or tokens in development and testing environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tokenization design is only as strong as its vault, access controls, and surrounding application behavior. If a service can freely resolve every token, tokenization alone does not provide meaningful isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apidog: Design and Test APIs with Authentication
&lt;/h2&gt;

&lt;p&gt;Implementing tokenization requires APIs that clearly define request formats, authentication rules, error responses, and token lifecycles. An API design and testing platform can help teams document these contracts and verify their behavior before deployment.&lt;/p&gt;

&lt;p&gt;Apidog can be used to design, document, debug, and test APIs. When integrating a tokenization service, define the token-related endpoints explicitly. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3.0.3&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/v1/tokens&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Tokenize a sensitive value&lt;/span&gt;
      &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;bearerAuth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
      &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
              &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;value&lt;/span&gt;
              &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
                  &lt;span class="na"&gt;writeOnly&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;201"&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Token created&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
                &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
                &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep sensitive fields marked as write-only where appropriate, and avoid documenting real credentials or production values in examples.&lt;/p&gt;

&lt;p&gt;You can configure common authentication schemes such as OAuth 2.0, Bearer tokens, and API keys. For tokenized workflows, define which credential is used to create a token and which credential is required to resolve one. These should not automatically be treated as the same permission.&lt;/p&gt;

&lt;p&gt;A useful test flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Submit a valid sensitive value to the tokenization endpoint.&lt;/li&gt;
&lt;li&gt;Verify that the response contains a token rather than the original value.&lt;/li&gt;
&lt;li&gt;Use the token in a downstream API request.&lt;/li&gt;
&lt;li&gt;Confirm that unauthorized clients cannot resolve the token.&lt;/li&gt;
&lt;li&gt;Verify that invalid, expired, or revoked tokens return the expected status code.&lt;/li&gt;
&lt;li&gt;Inspect logs and test output to confirm that raw values are not exposed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example test cases include:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST /v1/tokens with valid authorization       -&amp;gt; 201 Created
POST /v1/tokens without authorization          -&amp;gt; 401 Unauthorized
GET  /v1/records with a valid token            -&amp;gt; 200 OK
GET  /v1/records with an invalid token         -&amp;gt; 401 or 404
POST /v1/tokens with an oversized value        -&amp;gt; 400 Bad Request
Resolve a revoked token                        -&amp;gt; 401 or 404
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Environment variables can help pass non-sensitive test values, base URLs, and temporary credentials between requests. Do not place production secrets or real personal data in shared collections, exported projects, or test scripts.&lt;/p&gt;

&lt;p&gt;Apidog can also help keep the API contract aligned with OpenAPI, generate documentation, and run repeatable tests against tokenized workflows. Use it to verify both the expected success path and the security boundaries around token creation and resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Tokenization replaces sensitive data with opaque references, allowing applications to process and store tokens instead of raw values. The token itself should not reveal or mathematically encode the original data. Recovering the original value requires controlled access to the token vault.&lt;/p&gt;

&lt;p&gt;Tokenization and encryption solve different problems. Encryption protects data using algorithms and keys, while tokenization replaces data with a vault-managed reference. Many systems use both: TLS and encryption protect data in transit and at rest, while tokenization limits how many application components handle sensitive values.&lt;/p&gt;

&lt;p&gt;For a reliable implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tokenize sensitive fields as early as practical.&lt;/li&gt;
&lt;li&gt;Isolate the token vault from general application systems.&lt;/li&gt;
&lt;li&gt;Enforce separate permissions for token creation and resolution.&lt;/li&gt;
&lt;li&gt;Remove raw values from logs, traces, and test data.&lt;/li&gt;
&lt;li&gt;Define expiration, revocation, and audit requirements.&lt;/li&gt;
&lt;li&gt;Test unauthorized access and failure scenarios.&lt;/li&gt;
&lt;li&gt;Document the workflow with an explicit API contract.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is not a replacement for secure coding, access control, monitoring, or encryption. It is an additional boundary that can reduce sensitive-data exposure and simplify the design of APIs handling payment, healthcare, and personal information.&lt;/p&gt;

&lt;p&gt;Apidog can support this work by helping teams design the API contract, configure authentication, document tokenized fields, and test end-to-end request flows. Use those capabilities to validate that your tokenization workflow returns opaque tokens, protects the token vault, and never exposes raw data through ordinary application endpoints.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Can't Afford Postman? The Ultimate Postman Alternative for API Testing</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Fri, 28 Aug 2026 13:01:12 +0000</pubDate>
      <link>https://dev.to/preecha/cant-afford-postman-the-ultimate-postman-alternative-for-api-testing-55bh</link>
      <guid>https://dev.to/preecha/cant-afford-postman-the-ultimate-postman-alternative-for-api-testing-55bh</guid>
      <description>&lt;h1&gt;
  
  
  Postman vs Apidog: A Practical Migration Guide for Small API Teams
&lt;/h1&gt;

&lt;p&gt;On March 1, 2026, many developers received an unexpected pricing update: the popular free plan was restricted to a single user. For years, small agencies and technical startups used the free tier to collaborate with up to three team members. Teams that need multiple users must now move to the paid Team plan, priced at $19 per user per month when billed annually. This change has prompted many engineering teams to evaluate reliable Postman alternatives.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;For a small engineering team, collaboration is not optional. Shared workspaces, synchronized collections, repeatable tests, and fast feedback loops are part of the daily API development workflow. Moving from a free collaborative plan to a mandatory annual subscription can create a significant budget and adoption barrier.&lt;/p&gt;

&lt;p&gt;A practical Postman alternative should preserve the essentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send and inspect HTTP requests&lt;/li&gt;
&lt;li&gt;Mock server responses&lt;/li&gt;
&lt;li&gt;Validate API endpoints&lt;/li&gt;
&lt;li&gt;Run automated collections&lt;/li&gt;
&lt;li&gt;Share workspaces with teammates&lt;/li&gt;
&lt;li&gt;Reuse existing request scripts and environment variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Postman vs Apidog: Feature Comparison
&lt;/h2&gt;

&lt;p&gt;The comparison between Postman and Apidog is especially relevant for teams affected by the new free-plan restrictions. Postman remains useful for individuals who need to send requests and inspect responses. Apidog focuses more directly on API development teams that need design, testing, mocking, and collaboration in one workspace.&lt;/p&gt;

&lt;p&gt;The following table summarizes the plan differences described above:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Legacy tool free plan, March 2026&lt;/th&gt;
&lt;th&gt;Apidog free plan&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Team collaboration&lt;/td&gt;
&lt;td&gt;1 user&lt;/td&gt;
&lt;td&gt;Up to 4 active users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated collection runs&lt;/td&gt;
&lt;td&gt;25 runs per month&lt;/td&gt;
&lt;td&gt;Unlimited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API design&lt;/td&gt;
&lt;td&gt;Basic capabilities&lt;/td&gt;
&lt;td&gt;Visual schema builder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mock server&lt;/td&gt;
&lt;td&gt;Standard mocking limits&lt;/td&gt;
&lt;td&gt;Smart, continuous cloud mock&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary audience&lt;/td&gt;
&lt;td&gt;Solo API consumers&lt;/td&gt;
&lt;td&gt;Distributed API development teams&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For a small team, the difference is operational as well as financial. A one-user limit makes shared ownership more difficult, while a 25-run monthly limit can interrupt automated testing before a release cycle is complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use Apidog for API Testing?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmpj26ibfyi9bkerl86e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqmpj26ibfyi9bkerl86e.png" alt="Apidog: the best free Postman alternative" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apidog combines API design, request debugging, mocking, and automated validation in one interface. Consolidating these activities reduces the need to maintain separate tools for API documentation and testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Build tests visually
&lt;/h3&gt;

&lt;p&gt;A test workflow can be organized as a sequence of requests with dependencies between them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Authenticate the test user.&lt;/li&gt;
&lt;li&gt;Extract the returned token.&lt;/li&gt;
&lt;li&gt;Pass the token to subsequent requests.&lt;/li&gt;
&lt;li&gt;Create a resource.&lt;/li&gt;
&lt;li&gt;Assert the response status and body.&lt;/li&gt;
&lt;li&gt;Clean up the test data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This structure is useful for both QA engineers and backend developers because it makes request order, variables, and assertions visible to the team.&lt;/p&gt;

&lt;p&gt;A typical API test plan might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authenticate
  └── Extract access_token
        └── Create resource
              ├── Assert status is 201
              ├── Assert response contains resource ID
              └── Fetch resource and validate returned fields
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Reuse existing JavaScript
&lt;/h3&gt;

&lt;p&gt;If your current collections use custom pre-request scripts, Apidog supports reusing those JavaScript snippets. Before migrating, identify which scripts are responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating timestamps or signatures&lt;/li&gt;
&lt;li&gt;Creating random test data&lt;/li&gt;
&lt;li&gt;Setting authorization values&lt;/li&gt;
&lt;li&gt;Reading environment variables&lt;/li&gt;
&lt;li&gt;Preparing request bodies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a simple script that prepares a request value might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;requestId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`test-&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Reuse the equivalent environment-variable mechanism&lt;/span&gt;
&lt;span class="c1"&gt;// provided by your API testing workspace.&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestId&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Review each script after import and confirm that its variables are available in the new environment. This is particularly important for authentication and dynamic data generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Keep specifications, tests, and mocks aligned
&lt;/h3&gt;

&lt;p&gt;When an API specification changes, related tests and mock responses also need to change. Keeping these assets together helps reduce manual synchronization work as endpoints evolve.&lt;/p&gt;

&lt;p&gt;A useful maintenance workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update the endpoint or schema definition.&lt;/li&gt;
&lt;li&gt;Review the generated or associated request.&lt;/li&gt;
&lt;li&gt;Update assertions for changed fields.&lt;/li&gt;
&lt;li&gt;Verify the mock response.&lt;/li&gt;
&lt;li&gt;Run the relevant collection before merging the change.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This workflow limits the chance that documentation, mocks, and automated tests describe different versions of the same endpoint.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Run collections without the same monthly constraint
&lt;/h3&gt;

&lt;p&gt;Apidog’s free tier supports up to four active users and unlimited test and collection runs, according to the comparison above. That allows a small team to run regression checks repeatedly during development without planning around an arbitrary monthly run limit.&lt;/p&gt;

&lt;p&gt;Unlimited runs are useful when you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Re-run a failed test while debugging&lt;/li&gt;
&lt;li&gt;Execute a collection after every schema change&lt;/li&gt;
&lt;li&gt;Validate multiple environments&lt;/li&gt;
&lt;li&gt;Run a larger regression suite before release&lt;/li&gt;
&lt;li&gt;Let several teammates verify the same fix&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to Migrate Existing Collections
&lt;/h2&gt;

&lt;p&gt;Migrating tools does not need to interrupt active development. Use a staged process so that the original collections remain available until the new workspace is verified.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Inventory your current workspace
&lt;/h3&gt;

&lt;p&gt;Before exporting anything, list the assets your team actually uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collections and folders&lt;/li&gt;
&lt;li&gt;Environments&lt;/li&gt;
&lt;li&gt;Variables and secrets&lt;/li&gt;
&lt;li&gt;Authorization settings&lt;/li&gt;
&lt;li&gt;Pre-request scripts&lt;/li&gt;
&lt;li&gt;Tests and assertions&lt;/li&gt;
&lt;li&gt;Mock configurations&lt;/li&gt;
&lt;li&gt;Scheduled or automated runs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separate reusable configuration from sensitive values. Do not commit access tokens or production secrets to an exported file or source repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Export collections and environments
&lt;/h3&gt;

&lt;p&gt;Export the collections and environment files from the existing tool and store them in a temporary, access-controlled location. Keep a copy of the original export so you can compare results if an import does not behave as expected.&lt;/p&gt;

&lt;p&gt;For a request, verify that the following information survives the export:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://api.example.com/resources"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact export format depends on the source tool and collection version, but the migration checklist is the same: method, URL, headers, body, authentication, variables, scripts, and assertions should all be accounted for.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Import into the new workspace
&lt;/h3&gt;

&lt;p&gt;Use Apidog’s import tool to upload the collections and associated environment variables. After the import completes, open representative requests from each collection rather than assuming that every configuration migrated correctly.&lt;/p&gt;

&lt;p&gt;Check at least one example of each request type:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A public &lt;code&gt;GET&lt;/code&gt; request&lt;/li&gt;
&lt;li&gt;An authenticated request&lt;/li&gt;
&lt;li&gt;A request with path or query variables&lt;/li&gt;
&lt;li&gt;A request with a JSON body&lt;/li&gt;
&lt;li&gt;A request that depends on a previous response&lt;/li&gt;
&lt;li&gt;A request containing a pre-request script&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Reconfigure secrets safely
&lt;/h3&gt;

&lt;p&gt;Imported environment files may contain values that should not be shared with every workspace member. Replace exported credentials with safe placeholders and configure secrets using the workspace’s supported variable and permission controls.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API_BASE_URL=https://api.example.com
[REDACTED CREDENTIAL] securely&amp;gt;
TEST_USER_ID=&amp;lt;configure per environment&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use separate values for development, staging, and production. Avoid using production credentials while validating the migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Validate before switching the team
&lt;/h3&gt;

&lt;p&gt;Run a representative smoke test and compare its results with the original workspace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP status codes match&lt;/li&gt;
&lt;li&gt;Response headers are present&lt;/li&gt;
&lt;li&gt;Response bodies contain expected fields&lt;/li&gt;
&lt;li&gt;Variables are resolved correctly&lt;/li&gt;
&lt;li&gt;Authentication succeeds&lt;/li&gt;
&lt;li&gt;Assertions pass&lt;/li&gt;
&lt;li&gt;Mock responses match the intended schema&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Only after this validation should you invite the rest of the team and make the new workspace the default location for API testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collaboration Setup for a Four-Person Team
&lt;/h2&gt;

&lt;p&gt;The free Apidog plan supports up to four active users. A simple team setup might assign responsibilities as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API designer: maintains endpoint definitions and schemas&lt;/li&gt;
&lt;li&gt;Backend developer: implements and debugs endpoints&lt;/li&gt;
&lt;li&gt;QA engineer: maintains assertions and regression collections&lt;/li&gt;
&lt;li&gt;Product or integration developer: validates consumer-facing workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Define ownership for collections and environments before migrating. Clear ownership prevents duplicate requests, conflicting variable changes, and undocumented edits.&lt;/p&gt;

&lt;p&gt;You can also establish a lightweight review process:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create or update the API definition.&lt;/li&gt;
&lt;li&gt;Add or update the corresponding request.&lt;/li&gt;
&lt;li&gt;Add assertions for the expected behavior.&lt;/li&gt;
&lt;li&gt;Update the mock response if the contract changed.&lt;/li&gt;
&lt;li&gt;Ask another team member to run the collection.&lt;/li&gt;
&lt;li&gt;Merge the change only after the test passes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion: Choose a Postman Alternative That Fits Your Team
&lt;/h2&gt;

&lt;p&gt;The March 2026 pricing change transformed a previously collaborative free plan into a single-user option, with a 25-run monthly limit and a paid Team plan priced at $19 per user per month when billed annually. For small agencies, startups, and development teams, that can make shared API testing difficult to sustain.&lt;/p&gt;

&lt;p&gt;A reliable Postman replacement should protect both engineering velocity and the software budget. In the comparison above, Apidog addresses the main constraints by offering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Up to four active users on the free plan&lt;/li&gt;
&lt;li&gt;Unlimited test and collection runs&lt;/li&gt;
&lt;li&gt;Visual API design&lt;/li&gt;
&lt;li&gt;Integrated request testing&lt;/li&gt;
&lt;li&gt;Smart cloud mocking&lt;/li&gt;
&lt;li&gt;Support for reusing JavaScript snippets&lt;/li&gt;
&lt;li&gt;A single workspace for specifications, tests, and mocks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To evaluate the migration, export a representative collection, import it into Apidog, verify authentication and assertions, and then test the workflow with your team. This staged approach lets you validate compatibility before moving all active projects.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to use CLI-Anything: make any software agent-native</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Fri, 28 Aug 2026 02:02:11 +0000</pubDate>
      <link>https://dev.to/preecha/how-to-use-cli-anything-make-any-software-agent-native-75n</link>
      <guid>https://dev.to/preecha/how-to-use-cli-anything-make-any-software-agent-native-75n</guid>
      <description>&lt;h1&gt;
  
  
  CLI-Anything: Generate CLIs for GUI Applications Your AI Agent Can Use
&lt;/h1&gt;

&lt;p&gt;CLI-Anything is an open-source plugin for AI coding agents—primarily Claude Code—that generates a full command-line interface for software with an accessible codebase. Point it at GIMP, Blender, LibreOffice, or another application, and it analyzes the source code to produce a structured CLI that an AI agent can use programmatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: AI agents cannot use most GUI software directly
&lt;/h2&gt;

&lt;p&gt;Modern software is split between two worlds that rarely connect cleanly.&lt;/p&gt;

&lt;p&gt;API-first services such as cloud storage, payment processors, email providers, and analytics platforms expose HTTP APIs. An AI agent can call them directly with standard tools.&lt;/p&gt;

&lt;p&gt;Professional desktop software is different. GIMP, Blender, LibreOffice, and Audacity were primarily designed for people to operate through graphical interfaces. Their capabilities are exposed through menus, buttons, and dialogs rather than structured APIs.&lt;/p&gt;

&lt;p&gt;Connecting an AI agent to these applications usually means choosing between two imperfect approaches:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write a custom wrapper:&lt;/strong&gt; This can take weeks and may break when the application changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use robotic process automation (RPA):&lt;/strong&gt; RPA tools simulate clicks using screenshots, coordinates, or pixel matching. These workflows can break when layouts, themes, or display scaling change.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CLI-Anything takes a different approach. Instead of simulating GUI interactions, it analyzes the application's source code to find the APIs that the GUI already uses. It then generates a CLI that calls those APIs directly.&lt;/p&gt;

&lt;p&gt;The agent does not need to see the screen. It issues structured commands, and the target application performs the work.&lt;/p&gt;

&lt;p&gt;If your agent workflow also needs to call external REST APIs, &lt;a href="https://apidog.com/?ref=apidog.com" rel="noopener noreferrer"&gt;Apidog&lt;/a&gt; handles the API testing side. It is a free tool for sending, inspecting, and organizing API requests so you can verify integrations before adding them to your agent workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What CLI-Anything generates
&lt;/h2&gt;

&lt;p&gt;CLI-Anything is an open-source plugin built by HKUDS, the Hong Kong University Data Science Lab. Its creator, Chao Huang, described the project this way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Today's software serves humans. Tomorrow's users will be agents. CLI-Anything: bridging the gap between AI agents and the world's software. One command line to make any software agent-ready."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At the time of writing, the project has more than 6,100 GitHub stars.&lt;/p&gt;

&lt;p&gt;The plugin runs inside Claude Code and has experimental integrations for Codex and OpenCode. You point it at a software codebase, and it runs a seven-phase pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analyze&lt;/strong&gt; — Scan the source code, map GUI actions to underlying APIs, and produce a software-specific standard operating procedure document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design&lt;/strong&gt; — Define command groups, state models, and output formats.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement&lt;/strong&gt; — Build a Click-based Python CLI with REPL mode, &lt;code&gt;--json&lt;/code&gt; output, and undo/redo support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan tests&lt;/strong&gt; — Create a &lt;code&gt;TEST.md&lt;/code&gt; file containing unit and end-to-end test plans.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write tests&lt;/strong&gt; — Generate &lt;code&gt;test_core.py&lt;/code&gt; for unit tests with synthetic data and &lt;code&gt;test_full_e2e.py&lt;/code&gt; for tests using real files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document&lt;/strong&gt; — Run &lt;code&gt;pytest&lt;/code&gt; and append the results to &lt;code&gt;TEST.md&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Publish&lt;/strong&gt; — Create &lt;code&gt;setup.py&lt;/code&gt;, configure console-script entry points, and install the CLI on your &lt;code&gt;PATH&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After phase seven, you have a working CLI installed locally. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which cli-anything-gimp
cli-anything-gimp &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generated CLIs follow a consistent design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Human-readable table output by default&lt;/li&gt;
&lt;li&gt;Machine-readable JSON output with &lt;code&gt;--json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Persistent project state&lt;/li&gt;
&lt;li&gt;Undo/redo support&lt;/li&gt;
&lt;li&gt;Interactive REPL mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This consistency means an AI agent can reuse the same interaction patterns across different applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install CLI-Anything
&lt;/h2&gt;

&lt;p&gt;CLI-Anything is a Python-based plugin, not an npm package. You install it into your AI coding agent. The generated CLIs are Python packages installed with &lt;code&gt;pip install -e .&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Python 3.10 or later&lt;/li&gt;
&lt;li&gt;The target application installed on your system&lt;/li&gt;
&lt;li&gt;A supported AI coding agent:

&lt;ul&gt;
&lt;li&gt;Claude Code is the primary platform&lt;/li&gt;
&lt;li&gt;Codex and OpenCode integrations are experimental&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Claude Code
&lt;/h3&gt;

&lt;p&gt;In Claude Code, add the marketplace and install the plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add HKUDS/CLI-Anything
/plugin install cli-anything
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds the &lt;code&gt;/cli-anything&lt;/code&gt; slash commands to your Claude Code session.&lt;/p&gt;

&lt;h3&gt;
  
  
  OpenCode
&lt;/h3&gt;

&lt;p&gt;Clone the repository, then copy the command files and &lt;code&gt;HARNESS.md&lt;/code&gt; to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.config/opencode/commands/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything
/cli-anything-refine
/cli-anything-test
/cli-anything-validate
/cli-anything-list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Codex
&lt;/h3&gt;

&lt;p&gt;Run the installation script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash CLI-Anything/codex-skill/scripts/install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Qodercli
&lt;/h3&gt;

&lt;p&gt;Run the Qodercli setup script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash CLI-Anything/qoder-plugin/setup-qodercli.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Windows
&lt;/h3&gt;

&lt;p&gt;The plugin requires Git for Windows, which includes &lt;code&gt;bash&lt;/code&gt; and &lt;code&gt;cygpath&lt;/code&gt;, or WSL. Native Windows shell is not supported.&lt;/p&gt;

&lt;p&gt;If you see this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cygpath: command not found
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Git for Windows and retry.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install a generated CLI
&lt;/h3&gt;

&lt;p&gt;After CLI-Anything generates a harness, install it from the &lt;code&gt;agent-harness&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &amp;lt;software&amp;gt;/agent-harness
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Editable mode means changes to the generated source remain available without reinstalling the package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate your first CLI
&lt;/h2&gt;

&lt;p&gt;Once the plugin is installed, generation requires a single command.&lt;/p&gt;

&lt;p&gt;For a local GIMP codebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything ./gimp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a GitHub repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything https://github.com/blender/blender
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plugin starts the seven-phase pipeline. Generation takes a few minutes depending on the size of the codebase and the number of API surfaces it exposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens during analysis
&lt;/h3&gt;

&lt;p&gt;During phase one, CLI-Anything reads the source code and maps GUI actions to their underlying API calls.&lt;/p&gt;

&lt;p&gt;For GIMP, this can include operations such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating layers&lt;/li&gt;
&lt;li&gt;Applying filters&lt;/li&gt;
&lt;li&gt;Exporting files&lt;/li&gt;
&lt;li&gt;Managing projects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plugin writes a software-specific SOP document, such as &lt;code&gt;GIMP.md&lt;/code&gt;, describing the supported operations.&lt;/p&gt;

&lt;p&gt;During phase three, it builds the CLI with Python's Click framework. Commands support &lt;code&gt;--json&lt;/code&gt; output, and stateful operations—such as opening a file or creating a project—store state in a JSON file. The generated CLI also includes an interactive REPL with colored prompts and persistent history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generated directory structure
&lt;/h3&gt;

&lt;p&gt;A generated GIMP CLI may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gimp/
  agent-harness/
    GIMP.md           # Software SOP document
    setup.py
    cli_anything/     # Namespace package; no __init__.py (PEP 420)
      gimp/
        README.md
        gimp_cli.py   # Main CLI entry point
        core/         # Project, session, and export modules
        utils/        # REPL skin and helpers
        tests/
          test_core.py
          test_full_e2e.py
          TEST.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All generated CLIs use the &lt;code&gt;cli_anything.*&lt;/code&gt; namespace. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cli_anything.gimp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps prevent naming conflicts when you generate CLIs for multiple applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the generated CLI
&lt;/h2&gt;

&lt;p&gt;After installing the generated package, inspect the available commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;gimp/agent-harness
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;

cli-anything-gimp &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The naming convention is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cli-anything-&amp;lt;software&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Human-readable output
&lt;/h3&gt;

&lt;p&gt;Human-readable output is the default:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Start a new project&lt;/span&gt;
cli-anything-gimp project new &lt;span class="nt"&gt;--width&lt;/span&gt; 1920 &lt;span class="nt"&gt;--height&lt;/span&gt; 1080

&lt;span class="c"&gt;# List layers&lt;/span&gt;
cli-anything-gimp layer list

&lt;span class="c"&gt;# Add a layer&lt;/span&gt;
cli-anything-gimp layer add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Background"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; solid &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--color&lt;/span&gt; &lt;span class="s2"&gt;"#ffffff"&lt;/span&gt;

&lt;span class="c"&gt;# Apply a filter&lt;/span&gt;
cli-anything-gimp filter apply &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"gaussian-blur"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--radius&lt;/span&gt; 3

&lt;span class="c"&gt;# Export the project&lt;/span&gt;
cli-anything-gimp &lt;span class="nb"&gt;export &lt;/span&gt;save &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt; png &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; ./output.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JSON output for AI agents
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;--json&lt;/code&gt; when the caller needs machine-readable responses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-gimp &lt;span class="nt"&gt;--json&lt;/span&gt; project new &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--width&lt;/span&gt; 1920 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--height&lt;/span&gt; 1080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"proj_abc123"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"width"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1920&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"height"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1080&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another command might return:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-gimp &lt;span class="nt"&gt;--json&lt;/span&gt; layer add &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"Background"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"layer_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"layer_001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Background"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JSON format includes a &lt;code&gt;status&lt;/code&gt; field, operation-specific fields, and error details when an operation fails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interactive REPL mode
&lt;/h3&gt;

&lt;p&gt;For longer sessions, start the CLI without a subcommand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-gimp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The REPL provides colored prompts, tab completion, and persistent history. It is useful for exploring commands interactively before turning them into scripts or agent actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Undo and redo
&lt;/h3&gt;

&lt;p&gt;State-changing operations support a 50-level undo stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-gimp undo
cli-anything-gimp redo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Refine and test the generated CLI
&lt;/h2&gt;

&lt;p&gt;The first generated CLI may not cover every capability of the target application. CLI-Anything provides commands for gap analysis, testing, and validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Refine the CLI
&lt;/h3&gt;

&lt;p&gt;Run a general refinement pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything:refine /home/user/gimp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This compares the existing CLI with the application's API surface, identifies missing operations, and adds commands for the gaps.&lt;/p&gt;

&lt;p&gt;You can also focus refinement on a specific area:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything:refine /home/user/blender "particle systems and physics simulation"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The focused version targets the specified part of the codebase instead of re-analyzing everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the test suites
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything:test /home/user/gimp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs the test suites and updates &lt;code&gt;TEST.md&lt;/code&gt; with the results. The project reports more than 1,508 passing tests across 11 applications with a 100% pass rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  Validate the harness
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything:validate /home/user/gimp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validation checks the generated CLI harness against the &lt;code&gt;HARNESS.md&lt;/code&gt; specification and verifies that it meets the required structural conventions.&lt;/p&gt;

&lt;h3&gt;
  
  
  List generated CLIs
&lt;/h3&gt;

&lt;p&gt;List all available CLIs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything:list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request machine-readable output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything:list --json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Search in a specific directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/cli-anything:list --path /home
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Practical use cases
&lt;/h2&gt;

&lt;p&gt;CLI-Anything has been demonstrated with 11 applications. The following examples show how the generated commands can fit into real workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Batch image processing with GIMP
&lt;/h3&gt;

&lt;p&gt;An AI agent can resize product images, apply a watermark, and export multiple formats without interacting with the GUI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-gimp project open &lt;span class="nt"&gt;--file&lt;/span&gt; product.jpg

cli-anything-gimp layer add &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Watermark"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; image &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source&lt;/span&gt; watermark.png

cli-anything-gimp layer position &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Watermark"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--x&lt;/span&gt; 10 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--y&lt;/span&gt; 10

cli-anything-gimp &lt;span class="nb"&gt;export &lt;/span&gt;save &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt; webp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; product-final.webp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same command pattern can be applied repeatedly in a batch script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Document generation with LibreOffice
&lt;/h3&gt;

&lt;p&gt;LibreOffice can generate PDFs from templates. An agent can populate invoice, report, or contract data and export the result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-libreoffice document open &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--template&lt;/span&gt; invoice-template.ods

cli-anything-libreoffice cell &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--address&lt;/span&gt; &lt;span class="s2"&gt;"B5"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"Acme Corp"&lt;/span&gt;

cli-anything-libreoffice cell &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--address&lt;/span&gt; &lt;span class="s2"&gt;"C10"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"1500.00"&lt;/span&gt;

cli-anything-libreoffice &lt;span class="nb"&gt;export &lt;/span&gt;pdf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; invoice-2026-001.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3D rendering with Blender
&lt;/h3&gt;

&lt;p&gt;Blender render jobs can be configured and started without opening the GUI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-blender scene open &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--file&lt;/span&gt; product-scene.blend

cli-anything-blender render &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--samples&lt;/span&gt; 256 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--output&lt;/span&gt; /renders/product

cli-anything-blender render start &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt; png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Streaming automation with OBS Studio
&lt;/h3&gt;

&lt;p&gt;OBS workflows can be scripted for scene changes and recording controls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cli-anything-obs scene &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Main Camera"&lt;/span&gt;
cli-anything-obs recording start
cli-anything-obs scene &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"Screen Share"&lt;/span&gt;
cli-anything-obs recording stop &lt;span class="nt"&gt;--output&lt;/span&gt; session.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CI/CD integration
&lt;/h3&gt;

&lt;p&gt;Generated CLIs can run in CI/CD pipelines. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Render a Blender scene on every commit.&lt;/li&gt;
&lt;li&gt;Generate PDF release notes from a LibreOffice template.&lt;/li&gt;
&lt;li&gt;Process image assets during a build.&lt;/li&gt;
&lt;li&gt;Run the generated CLI's tests as part of validation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Combine local CLIs with external APIs
&lt;/h2&gt;

&lt;p&gt;CLI-Anything handles local desktop software. Production agent workflows often need external APIs as well—for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload a processed image to a CDN.&lt;/li&gt;
&lt;li&gt;Send a generated PDF to a document management system.&lt;/li&gt;
&lt;li&gt;Upload a rendered video to a review platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Apidog handles the API testing side. It is a free API client for testing, documenting, and automating REST API calls.&lt;/p&gt;

&lt;p&gt;For example, suppose you are building an agent that processes product images with GIMP and uploads them to cloud storage. CLI-Anything gives the agent the GIMP commands, while Apidog helps you verify the storage API before writing the integration.&lt;/p&gt;

&lt;p&gt;In Apidog, you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an environment and store API credentials as variables.&lt;/li&gt;
&lt;li&gt;Test the upload endpoint with a sample file.&lt;/li&gt;
&lt;li&gt;Verify that the request format is correct.&lt;/li&gt;
&lt;li&gt;Add assertions that confirm the response includes the expected file URL.&lt;/li&gt;
&lt;li&gt;Export the working request as a &lt;code&gt;curl&lt;/code&gt; command or code snippet.&lt;/li&gt;
&lt;li&gt;Add the request to your agent script.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This separates two potential failure points. You can confirm that the external API works before debugging the GIMP workflow and the API integration at the same time.&lt;/p&gt;

&lt;p&gt;Apidog also supports automated test suites. Once the workflow works, add assertions that run during each execution to catch regressions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Windows requires Git Bash or WSL
&lt;/h3&gt;

&lt;p&gt;Generated CLIs are Python applications that rely on bash-style path handling. Windows users need Git for Windows, which includes Bash and &lt;code&gt;cygpath&lt;/code&gt;, or WSL. Native PowerShell is not supported.&lt;/p&gt;

&lt;h3&gt;
  
  
  The target software must already be installed
&lt;/h3&gt;

&lt;p&gt;CLI-Anything does not bundle the applications it wraps. GIMP, Blender, LibreOffice, and other target applications must be installed on the same machine as the generated CLI.&lt;/p&gt;

&lt;p&gt;The CLI calls the real application backends directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generated CLIs are Python-only
&lt;/h3&gt;

&lt;p&gt;CLI-Anything generates Python Click applications. It does not generate wrappers in other languages. If you need a Node.js or Go CLI, you must build that wrapper separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Claude Code is the stable platform
&lt;/h3&gt;

&lt;p&gt;Claude Code is the primary and most-tested environment. Codex and OpenCode integrations are experimental, so behavior may vary outside Claude Code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generation quality depends on the codebase
&lt;/h3&gt;

&lt;p&gt;The plugin must identify the APIs behind GUI actions. If the codebase is poorly structured, heavily obfuscated, or tightly coupled to GUI state, the analysis may miss commands or produce incomplete wrappers.&lt;/p&gt;

&lt;p&gt;The refinement workflow can improve coverage, but complex proprietary software may be more difficult to wrap cleanly.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does CLI-Anything work with any software?
&lt;/h3&gt;

&lt;p&gt;In principle, CLI-Anything can generate a CLI for software with an accessible codebase. In practice, it works best with open-source applications where GUI actions map clearly to underlying API calls.&lt;/p&gt;

&lt;p&gt;The project has demonstrated support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GIMP&lt;/li&gt;
&lt;li&gt;Blender&lt;/li&gt;
&lt;li&gt;Inkscape&lt;/li&gt;
&lt;li&gt;Audacity&lt;/li&gt;
&lt;li&gt;Kdenlive&lt;/li&gt;
&lt;li&gt;Shotcut&lt;/li&gt;
&lt;li&gt;OBS Studio&lt;/li&gt;
&lt;li&gt;Draw.io&lt;/li&gt;
&lt;li&gt;LibreOffice&lt;/li&gt;
&lt;li&gt;AnyGen&lt;/li&gt;
&lt;li&gt;Zoom&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Is the project free to use?
&lt;/h3&gt;

&lt;p&gt;Yes. CLI-Anything is MIT licensed and fully open source at &lt;code&gt;github.com/HKUDS/CLI-Anything&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to know Python?
&lt;/h3&gt;

&lt;p&gt;No. The plugin generates the Python code for you. You do need Python 3.10 or later installed to run the generated CLIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I call the generated CLI from my own code?
&lt;/h3&gt;

&lt;p&gt;Yes. The generated CLI is a standard command-line tool. You can call it from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shell scripts&lt;/li&gt;
&lt;li&gt;Makefiles&lt;/li&gt;
&lt;li&gt;Python programs&lt;/li&gt;
&lt;li&gt;CI/CD jobs&lt;/li&gt;
&lt;li&gt;Any program that can run a subprocess&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What is &lt;code&gt;HARNESS.md&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;HARNESS.md&lt;/code&gt; defines the expected structure of a CLI-Anything-generated harness. It covers command structure, output formats, testing requirements, and packaging.&lt;/p&gt;

&lt;p&gt;The validation command checks the generated CLI against this specification.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I generate CLIs for internal tools?
&lt;/h3&gt;

&lt;p&gt;Yes. You can point the plugin at any local codebase, including private internal tools. The plugin runs locally and does not send your source code elsewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does CLI-Anything compare with Model Context Protocol (MCP)?
&lt;/h3&gt;

&lt;p&gt;MCP connects AI agents to external services through a standardized server protocol. CLI-Anything generates local CLI wrappers for GUI applications that do not expose usable APIs.&lt;/p&gt;

&lt;p&gt;They solve different problems. You can use both:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP for cloud and external services&lt;/li&gt;
&lt;li&gt;CLI-Anything for local desktop software&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Additional resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CLI-Anything GitHub repository&lt;/li&gt;
&lt;li&gt;CLI-Anything official website&lt;/li&gt;
&lt;li&gt;Community guide&lt;/li&gt;
&lt;li&gt;Apidog free API client&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to install and use the Resend CLI</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Fri, 28 Aug 2026 01:01:45 +0000</pubDate>
      <link>https://dev.to/preecha/how-to-install-and-use-the-resend-cli-33ne</link>
      <guid>https://dev.to/preecha/how-to-install-and-use-the-resend-cli-33ne</guid>
      <description>&lt;h1&gt;
  
  
  Resend CLI: Send and Manage Email from the Terminal
&lt;/h1&gt;

&lt;p&gt;The Resend CLI is the official command-line tool for Resend, an email platform built for developers. Install it with &lt;code&gt;npm install -g resend-cli&lt;/code&gt; or &lt;code&gt;brew install resend/cli/resend&lt;/code&gt;, authenticate with &lt;code&gt;resend login&lt;/code&gt;, and then send emails, manage domains, and automate email infrastructure from a terminal or CI/CD pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Resend?
&lt;/h2&gt;

&lt;p&gt;Resend is an email API for developers. Connect a domain, create an API key, and start sending transactional emails from your application, including password resets, order confirmations, and onboarding messages.&lt;/p&gt;

&lt;p&gt;On March 13, 2026, Resend founder Zeno Rocha shipped the Resend CLI, bringing the same infrastructure to the terminal. The CLI has 53 commands across 13 resources, is written in TypeScript, and is fully open source under the MIT license.&lt;/p&gt;

&lt;p&gt;It supports three common use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Humans:&lt;/strong&gt; Interactive prompts, readable tables, and natural-language scheduling such as &lt;code&gt;tomorrow at 9am&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI agents:&lt;/strong&gt; JSON output, idempotency keys, and automatic agent detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI/CD pipelines:&lt;/strong&gt; Environment-variable authentication, scriptable flags, and consistent exit codes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building an application that sends email, test your email API calls before they reach production. &lt;a href="https://apidog.com/?ref=apidog.com" rel="noopener noreferrer"&gt;Apidog&lt;/a&gt; provides a visual interface for testing REST APIs, including Resend's email API. You can import the Resend OpenAPI specification, configure environments, and run organized test suites without writing additional test code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing the Resend CLI
&lt;/h2&gt;

&lt;p&gt;Choose the installation method that best fits your environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install with cURL
&lt;/h3&gt;

&lt;p&gt;This method downloads a standalone binary and does not require Node.js:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://resend.com/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer downloads a prebuilt binary for your operating system and places it on your &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install with npm
&lt;/h3&gt;

&lt;p&gt;The npm package requires Node.js 20 or later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; resend-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install with Homebrew
&lt;/h3&gt;

&lt;p&gt;On macOS or Linux, install the CLI with Homebrew:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;resend/cli/resend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Homebrew also handles future updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install on Windows with PowerShell
&lt;/h3&gt;

&lt;p&gt;Run the PowerShell installer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://resend.com/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also download &lt;code&gt;.exe&lt;/code&gt; binaries directly from the GitHub Releases page.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build the CLI locally
&lt;/h3&gt;

&lt;p&gt;To contribute to the CLI or build it from source, install Node.js 20 or later and pnpm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/resend/resend-cli.git
&lt;span class="nb"&gt;cd &lt;/span&gt;resend-cli
pnpm &lt;span class="nb"&gt;install
&lt;/span&gt;pnpm build       &lt;span class="c"&gt;# outputs ./dist/cli.cjs&lt;/span&gt;
pnpm build:bin   &lt;span class="c"&gt;# native binary at ./dist/resend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Authenticating your account
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;resend login&lt;/code&gt; to connect the CLI to your Resend account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command opens your browser and guides you through creating an API key in the Resend dashboard. Credentials are stored locally at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.config/resend/credentials.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The file uses restricted &lt;code&gt;0600&lt;/code&gt; permissions.&lt;/p&gt;

&lt;p&gt;For CI/CD pipelines and other non-interactive environments, pass an API key directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend login &lt;span class="nt"&gt;--key&lt;/span&gt; re_xxxxxxxxxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After authentication, the CLI resolves API keys in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;--api-key&lt;/code&gt; flag&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;RESEND_API_KEY&lt;/code&gt; environment variable&lt;/li&gt;
&lt;li&gt;The stored credentials file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For CI pipelines, store &lt;code&gt;RESEND_API_KEY&lt;/code&gt; as a secret environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;RESEND_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;re_xxx &lt;span class="se"&gt;\&lt;/span&gt;
  resend emails send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; builds@yourco.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; dev@yourco.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Build passed"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"All tests green."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use multiple accounts
&lt;/h3&gt;

&lt;p&gt;If you work with multiple Resend organizations or teams, switch between stored profiles without logging out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend auth switch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also select a profile for one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend &amp;lt;&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nt"&gt;--profile&lt;/span&gt; production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Sending your first email
&lt;/h2&gt;

&lt;p&gt;The main sending command is &lt;code&gt;resend emails send&lt;/code&gt;. At minimum, provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A sender address from a verified domain&lt;/li&gt;
&lt;li&gt;A recipient&lt;/li&gt;
&lt;li&gt;A subject&lt;/li&gt;
&lt;li&gt;A message body&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Send a plain-text email
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; &lt;span class="s2"&gt;"you@yourdomain.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; recipient@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Hello from the CLI"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"This is a test email sent from the Resend CLI."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Send an HTML email
&lt;/h3&gt;

&lt;p&gt;Pass HTML inline with &lt;code&gt;--html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; &lt;span class="s2"&gt;"team@yourco.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; user@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Your order is confirmed"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--html&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;h1&amp;gt;Order confirmed&amp;lt;/h1&amp;gt;&amp;lt;p&amp;gt;Thanks for your purchase.&amp;lt;/p&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For larger templates, use &lt;code&gt;--html-file&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; &lt;span class="s2"&gt;"team@yourco.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; user@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Welcome aboard"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--html-file&lt;/span&gt; ./templates/welcome.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Schedule delivery
&lt;/h3&gt;

&lt;p&gt;The CLI accepts natural-language dates as well as ISO 8601 timestamps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; &lt;span class="s2"&gt;"you@yourco.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; user@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Scheduled check-in"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"Just checking in."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--schedule&lt;/span&gt; &lt;span class="s2"&gt;"tomorrow at 9am"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Other supported formats include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;in 1 hour&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;next Monday at 3pm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A complete ISO 8601 timestamp&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Capture the email ID
&lt;/h3&gt;

&lt;p&gt;When output is piped, the CLI automatically switches to JSON output. Use &lt;code&gt;jq&lt;/code&gt; to extract the email ID:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;EMAIL_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;resend emails send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; a@acme.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; b@acme.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Test"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"Hi"&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.data.id'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Sent email: &lt;/span&gt;&lt;span class="nv"&gt;$EMAIL_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use the ID for follow-up operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cancel or update a scheduled email
&lt;/h3&gt;

&lt;p&gt;Cancel a scheduled email:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails cancel &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EMAIL_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update its schedule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails update &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EMAIL_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--schedule&lt;/span&gt; &lt;span class="s2"&gt;"next Monday at 10am"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  List recent emails
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Send a batch of emails
&lt;/h3&gt;

&lt;p&gt;The CLI supports batches of up to 100 emails. Create a JSON file containing an array of email objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"you@yourco.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alice@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi Alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello!"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"you@yourco.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bob@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"subject"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hi Bob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello!"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send the batch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails send-batch &lt;span class="nt"&gt;--file&lt;/span&gt; emails.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each batch request counts as one API call against your rate limit, even when it sends up to 100 emails.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing domains and API keys
&lt;/h2&gt;

&lt;p&gt;You need a verified domain before you can send email. The CLI supports the complete domain setup and verification workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add a domain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend domains create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; yourdomain.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Supported regions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;us-east-1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eu-west-1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sa-east-1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ap-northeast-1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose the region closest to your users to minimize latency.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify DNS records
&lt;/h3&gt;

&lt;p&gt;After you create a domain, Resend provides DNS records to add to your DNS provider, including SPF, DKIM, and DMARC records.&lt;/p&gt;

&lt;p&gt;Start verification with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend domains verify &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;domain-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the domain status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend domains get &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;domain-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Poll the status until it returns &lt;code&gt;verified&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure tracking and TLS
&lt;/h3&gt;

&lt;p&gt;Run the interactive configuration command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend domains configure &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;domain-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets you configure options such as open tracking, click tracking, and custom DKIM.&lt;/p&gt;

&lt;h3&gt;
  
  
  List domains
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend domains list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Manage API keys
&lt;/h3&gt;

&lt;p&gt;Create scoped API keys for individual services or environments instead of sharing one key everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend api-keys create  &lt;span class="c"&gt;# Interactive, lets you scope per domain&lt;/span&gt;
resend api-keys list
resend api-keys delete &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;key-id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A key scoped to one domain cannot access your other domains or account settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advanced features
&lt;/h2&gt;

&lt;p&gt;In addition to individual emails, the CLI supports broadcasts, webhooks, templates, contacts, and audiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Broadcasts
&lt;/h3&gt;

&lt;p&gt;Create a broadcast draft, then send or schedule it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend broadcasts create   &lt;span class="c"&gt;# Interactive draft creation&lt;/span&gt;
resend broadcasts send &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;broadcast-id&amp;gt;
resend broadcasts schedule &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;broadcast-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--date&lt;/span&gt; &lt;span class="s2"&gt;"next Monday at 10am"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Webhooks
&lt;/h3&gt;

&lt;p&gt;Webhooks provide real-time delivery events such as bounces, opens, clicks, and spam reports.&lt;/p&gt;

&lt;p&gt;Create and list webhook endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend webhooks create   &lt;span class="c"&gt;# Register a new endpoint&lt;/span&gt;
resend webhooks list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For local development, forward webhook events to a local endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend webhooks listen &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--forward-to&lt;/span&gt; http://localhost:3000/webhooks/resend
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This avoids setting up ngrok or similar tunneling tools. The CLI supports 17 event types, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;email.sent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email.delivered&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email.bounced&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email.opened&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email.clicked&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Templates
&lt;/h3&gt;

&lt;p&gt;Create reusable HTML templates with dynamic variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend templates create  &lt;span class="c"&gt;# Interactive template builder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Template variables use the &lt;code&gt;{{variable_name}}&lt;/code&gt; syntax with fallback values. Reference a template by ID when sending emails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Contacts and audiences
&lt;/h3&gt;

&lt;p&gt;Resend also provides contact management for marketing emails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend contacts create &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--audience-id&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--email&lt;/span&gt; user@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--first-name&lt;/span&gt; &lt;span class="s2"&gt;"Alice"&lt;/span&gt;

resend contacts list &lt;span class="nt"&gt;--audience-id&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

resend contacts update &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;contact-id&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unsubscribed&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run diagnostics
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;doctor&lt;/code&gt; command checks your local setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend doctor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It verifies your CLI version, API key validity, and verified domains. It can also detect AI coding agents such as Cursor, Claude Desktop, VS Code, and OpenClaw.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Resend CLI in CI/CD pipelines
&lt;/h2&gt;

&lt;p&gt;The CLI is designed for automated environments. Use non-interactive authentication, machine-readable output, and automatic confirmation flags in scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use machine-readable output
&lt;/h3&gt;

&lt;p&gt;Pass &lt;code&gt;--json&lt;/code&gt; to force structured JSON output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from&lt;/span&gt; a@co.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; b@co.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Deploy"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"Done"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI also automatically uses JSON when its output is piped.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--quiet&lt;/code&gt; flag suppresses spinners and progress indicators:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend emails list &lt;span class="nt"&gt;--quiet&lt;/span&gt; | jq &lt;span class="s1"&gt;'.[0].id'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Skip confirmation prompts
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;--yes&lt;/code&gt; for destructive operations in scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;resend api-keys delete &lt;span class="nt"&gt;--id&lt;/span&gt; &amp;lt;key-id&amp;gt; &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitHub Actions example
&lt;/h3&gt;

&lt;p&gt;Store the API key in GitHub Actions secrets and expose it only to the step that needs it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Send deployment notification&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;RESEND_API_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.RESEND_API_KEY }}&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;resend emails send \&lt;/span&gt;
      &lt;span class="s"&gt;--from deploys@yourco.com \&lt;/span&gt;
      &lt;span class="s"&gt;--to team@yourco.com \&lt;/span&gt;
      &lt;span class="s"&gt;--subject "Deploy to production: ${{ github.sha }}" \&lt;/span&gt;
      &lt;span class="s"&gt;--text "Deployed commit ${{ github.sha }} to production."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Account for rate limits
&lt;/h3&gt;

&lt;p&gt;The Resend API rate limit is two requests per second, shared across all API keys for your team.&lt;/p&gt;

&lt;p&gt;When sending multiple messages, prefer &lt;code&gt;send-batch&lt;/code&gt;—which supports up to 100 emails per call—instead of looping over individual &lt;code&gt;send&lt;/code&gt; commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing your email API with Apidog
&lt;/h2&gt;

&lt;p&gt;The Resend CLI works well for interactive development and simple scripts. If your backend calls Resend's REST API directly, an API client can help you explore and test the integration before writing application code.&lt;/p&gt;

&lt;p&gt;Apidog lets you send HTTP requests, inspect responses, organize test cases, and configure separate environments for different API keys and settings.&lt;/p&gt;

&lt;p&gt;A typical workflow looks like this:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Import the Resend API specification
&lt;/h3&gt;

&lt;p&gt;Resend provides API reference documentation at &lt;code&gt;resend.com/docs&lt;/code&gt;. Import the API specification into Apidog to organize the available endpoints and view their request and response schemas.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Configure environments
&lt;/h3&gt;

&lt;p&gt;Create development and production environments. Store your &lt;code&gt;RESEND_API_KEY&lt;/code&gt; as an environment variable and reference it in requests with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{{RESEND_API_KEY}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can switch between environments without manually replacing credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Test the sending request
&lt;/h3&gt;

&lt;p&gt;Before implementing the integration in your application, run the &lt;code&gt;POST /emails&lt;/code&gt; endpoint with the payload you plan to use.&lt;/p&gt;

&lt;p&gt;Verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The response status&lt;/li&gt;
&lt;li&gt;The returned email ID&lt;/li&gt;
&lt;li&gt;Required-field validation&lt;/li&gt;
&lt;li&gt;Invalid-address behavior&lt;/li&gt;
&lt;li&gt;Other edge cases relevant to your application&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Automate API tests
&lt;/h3&gt;

&lt;p&gt;Use Apidog's test runner to chain requests and assert response values. For example, a test can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send a test email&lt;/li&gt;
&lt;li&gt;Retrieve it by ID&lt;/li&gt;
&lt;li&gt;Verify its status&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This catches integration problems before they reach production. Combined with the Resend CLI for local development, you have a terminal workflow for quick checks and an API testing environment for repeatable integration tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resend pricing
&lt;/h2&gt;

&lt;p&gt;The CLI is free and open source. Pricing applies to the Resend platform:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Monthly emails&lt;/th&gt;
&lt;th&gt;Daily limit&lt;/th&gt;
&lt;th&gt;Log retention&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0/month&lt;/td&gt;
&lt;td&gt;3,000&lt;/td&gt;
&lt;td&gt;100/day&lt;/td&gt;
&lt;td&gt;1 day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;$20/month&lt;/td&gt;
&lt;td&gt;50,000&lt;/td&gt;
&lt;td&gt;No limit&lt;/td&gt;
&lt;td&gt;3 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scale&lt;/td&gt;
&lt;td&gt;$90/month&lt;/td&gt;
&lt;td&gt;100,000&lt;/td&gt;
&lt;td&gt;No limit&lt;/td&gt;
&lt;td&gt;7 days&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Important free-tier details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The 100-email-per-day limit makes the free plan suitable for testing and small projects, not production traffic.&lt;/li&gt;
&lt;li&gt;Analytics such as open and click tracking require a paid plan.&lt;/li&gt;
&lt;li&gt;Log retention is limited to one day, so old email status may not be retrievable after 24 hours.&lt;/li&gt;
&lt;li&gt;The rate limit is two requests per second for all plans, shared across your team.&lt;/li&gt;
&lt;li&gt;Overage on paid plans is capped at five times the monthly quota to help prevent unexpected bills.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dedicated IPs are available as a $30/month add-on on the Scale plan when sending more than 500 emails per day.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do I need Node.js to install the Resend CLI?
&lt;/h3&gt;

&lt;p&gt;Not when using cURL or Homebrew, which install prebuilt standalone binaries. The npm installation requires Node.js 20 or later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why can't I send from any email address?
&lt;/h3&gt;

&lt;p&gt;Resend requires a verified domain. You must own the domain, add the SPF, DKIM, and DMARC records provided by Resend, and complete verification. Free email providers such as Gmail are not supported as sender addresses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I send to any email address on the free plan?
&lt;/h3&gt;

&lt;p&gt;Yes. The free plan does not restrict recipients, but it limits you to 3,000 emails per month and 100 emails per day.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does natural-language scheduling work?
&lt;/h3&gt;

&lt;p&gt;The CLI parses phrases such as &lt;code&gt;tomorrow at 9am&lt;/code&gt;, &lt;code&gt;in 2 hours&lt;/code&gt;, and &lt;code&gt;next Friday at 3pm&lt;/code&gt;, as well as standard ISO 8601 timestamps. Unless you specify otherwise, times are interpreted in your system's local timezone.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens when I pipe output?
&lt;/h3&gt;

&lt;p&gt;The CLI detects when output is being piped and automatically switches to JSON-only output without spinners or prompts. You do not need to pass &lt;code&gt;--json&lt;/code&gt; explicitly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use the CLI with multiple Resend accounts?
&lt;/h3&gt;

&lt;p&gt;Yes. Run &lt;code&gt;resend login&lt;/code&gt; multiple times to store different profiles. Then use &lt;code&gt;resend auth switch&lt;/code&gt; to change profiles, or pass &lt;code&gt;--profile &amp;lt;name&amp;gt;&lt;/code&gt; to a specific command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the Resend CLI open source?
&lt;/h3&gt;

&lt;p&gt;Yes. It is MIT licensed and hosted at &lt;code&gt;github.com/resend/resend-cli&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between &lt;code&gt;--quiet&lt;/code&gt; and &lt;code&gt;--json&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Both produce JSON output. &lt;code&gt;--json&lt;/code&gt; forces JSON mode, while &lt;code&gt;--quiet&lt;/code&gt; suppresses spinners and progress indicators and also implies JSON mode. In practice, they use the same output format; &lt;code&gt;--quiet&lt;/code&gt; additionally removes non-data output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Resend CLI GitHub repository&lt;/li&gt;
&lt;li&gt;Resend documentation&lt;/li&gt;
&lt;li&gt;Resend pricing&lt;/li&gt;
&lt;li&gt;Resend changelog&lt;/li&gt;
&lt;li&gt;Apidog free API client&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How to install and use the Context7 CLI</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Thu, 27 Aug 2026 14:01:55 +0000</pubDate>
      <link>https://dev.to/preecha/how-to-install-and-use-the-context7-cli-7b9</link>
      <guid>https://dev.to/preecha/how-to-install-and-use-the-context7-cli-7b9</guid>
      <description>&lt;p&gt;Context7 injects up-to-date library documentation directly into your AI coding assistant's context, helping it avoid generating code from stale training data. The &lt;code&gt;ctx7&lt;/code&gt; CLI runs with &lt;code&gt;npx ctx7&lt;/code&gt; without installation and connects to Claude Code, Cursor, or OpenCode with a single &lt;code&gt;ctx7 setup&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Context7 and why does it matter?
&lt;/h2&gt;

&lt;p&gt;AI coding assistants can generate code that looks correct but uses APIs that no longer exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Function signatures may be outdated.&lt;/li&gt;
&lt;li&gt;Import paths may have changed.&lt;/li&gt;
&lt;li&gt;Examples may target an older major version.&lt;/li&gt;
&lt;li&gt;Deprecated APIs may still appear in generated code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This happens because LLMs are trained on data with a cutoff date. They may not know about recent changes, such as a framework changing its layout system or a library deprecating a large part of its API.&lt;/p&gt;

&lt;p&gt;Context7 solves this by indexing documentation for more than 9,000 libraries and serving it to your AI assistant in real time. When you ask your coding agent a question, Context7 fetches current, version-specific documentation and adds it to the model's context before it generates a response.&lt;/p&gt;

&lt;p&gt;The result is code that is more closely aligned with the APIs and documentation available today.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ctx7&lt;/code&gt; CLI is Context7's command-line interface. It can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch library documentation from your terminal&lt;/li&gt;
&lt;li&gt;Manage AI coding skills, which are reusable prompt files for your agent&lt;/li&gt;
&lt;li&gt;Configure the Context7 MCP server for Claude Code, Cursor, or OpenCode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building API integrations alongside your development work, &lt;a href="https://apidog.com/?ref=apidog.com" rel="noopener noreferrer"&gt;Apidog&lt;/a&gt; handles the API testing side. It's a free client for sending, organizing, and automating API requests. Context7 keeps your AI assistant's knowledge current, while Apidog helps you verify the API calls your application makes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install &lt;code&gt;ctx7&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The only requirement is Node.js 18 or later. Check your installed version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run without installing
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;npx&lt;/code&gt; to try the CLI without installing it globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx ctx7 &lt;span class="nt"&gt;--help&lt;/span&gt;
npx ctx7 library react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;npx&lt;/code&gt; downloads the latest version when you run the command. This is convenient for occasional use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install globally
&lt;/h3&gt;

&lt;p&gt;For regular use, install &lt;code&gt;ctx7&lt;/code&gt; globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; ctx7
ctx7 &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Global installation lets you run commands locally without the &lt;code&gt;npx&lt;/code&gt; download overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up Context7 for your AI coding agent
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ctx7 setup&lt;/code&gt; command connects Context7 to your AI coding environment. It authenticates through OAuth, generates an API key, and writes the configuration to the appropriate location.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the interactive setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI prompts you to select your agent and preferred mode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLI + Skills&lt;/li&gt;
&lt;li&gt;MCP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To accept the default options without prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 setup &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Target a specific agent
&lt;/h3&gt;

&lt;p&gt;Use an agent-specific flag when you already know which environment you want to configure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 setup &lt;span class="nt"&gt;--claude&lt;/span&gt;     &lt;span class="c"&gt;# Claude Code (~/.claude/skills or MCP config)&lt;/span&gt;
ctx7 setup &lt;span class="nt"&gt;--cursor&lt;/span&gt;     &lt;span class="c"&gt;# Cursor (~/.cursor/skills or MCP config)&lt;/span&gt;
ctx7 setup &lt;span class="nt"&gt;--opencode&lt;/span&gt;   &lt;span class="c"&gt;# OpenCode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use an existing API key
&lt;/h3&gt;

&lt;p&gt;If you already have a Context7 API key from &lt;code&gt;context7.com/dashboard&lt;/code&gt;, pass it during setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 setup &lt;span class="nt"&gt;--api-key&lt;/span&gt; YOUR_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure a project instead of your whole system
&lt;/h3&gt;

&lt;p&gt;By default, &lt;code&gt;ctx7 setup&lt;/code&gt; installs configuration globally. To configure only the current project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 setup &lt;span class="nt"&gt;--project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Choose between CLI + Skills and MCP
&lt;/h2&gt;

&lt;p&gt;Context7 supports two setup modes.&lt;/p&gt;

&lt;h3&gt;
  
  
  CLI + Skills mode
&lt;/h3&gt;

&lt;p&gt;CLI + Skills mode installs a &lt;code&gt;SKILL.md&lt;/code&gt; file that instructs your AI agent to fetch documentation by running &lt;code&gt;ctx7&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;When the agent needs library documentation, it can run commands such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 library react
ctx7 docs /facebook/react &lt;span class="s2"&gt;"useEffect cleanup"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No MCP server is required.&lt;/p&gt;

&lt;p&gt;Install the skill for a specific agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 setup &lt;span class="nt"&gt;--cli&lt;/span&gt; &lt;span class="nt"&gt;--claude&lt;/span&gt;
ctx7 setup &lt;span class="nt"&gt;--cli&lt;/span&gt; &lt;span class="nt"&gt;--cursor&lt;/span&gt;
ctx7 setup &lt;span class="nt"&gt;--cli&lt;/span&gt; &lt;span class="nt"&gt;--universal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The universal option installs the skill at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.config/agents/skills
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  MCP Server mode
&lt;/h3&gt;

&lt;p&gt;MCP mode registers Context7 as a Model Context Protocol server. Your agent can then call &lt;code&gt;resolve-library-id&lt;/code&gt; and &lt;code&gt;query-docs&lt;/code&gt; natively, without running CLI commands explicitly.&lt;/p&gt;

&lt;p&gt;An MCP configuration looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://mcp.context7.com/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"CONTEXT7_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"YOUR_API_KEY"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also add Context7 to Claude Code from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--scope&lt;/span&gt; user context7 &lt;span class="nt"&gt;--&lt;/span&gt; npx &lt;span class="nt"&gt;-y&lt;/span&gt; @upstash/context7-mcp &lt;span class="nt"&gt;--api-key&lt;/span&gt; YOUR_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MCP mode makes documentation fetching less visible in your workflow because the agent calls the tools directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authenticate with Context7
&lt;/h2&gt;

&lt;p&gt;Use these commands to manage your Context7 session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 login    &lt;span class="c"&gt;# OAuth browser login&lt;/span&gt;
ctx7 &lt;span class="nb"&gt;whoami&lt;/span&gt;   &lt;span class="c"&gt;# Confirm your current session&lt;/span&gt;
ctx7 &lt;span class="nb"&gt;logout&lt;/span&gt;   &lt;span class="c"&gt;# Remove stored credentials&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also provide your API key through an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONTEXT7_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;your_key_here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Login is required for skill generation and some setup flows. Basic documentation lookups work without authentication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disable telemetry
&lt;/h3&gt;

&lt;p&gt;Context7 collects anonymous usage data by default. To disable it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CTX7_TELEMETRY_DISABLED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fetch library documentation from the terminal
&lt;/h2&gt;

&lt;p&gt;You can use &lt;code&gt;ctx7&lt;/code&gt; as a standalone documentation lookup tool, even without an AI coding agent.&lt;/p&gt;

&lt;p&gt;Two commands provide the main workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Resolve a library name.&lt;/li&gt;
&lt;li&gt;Fetch documentation for a topic.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Resolve a library
&lt;/h3&gt;

&lt;p&gt;Search the Context7 index with &lt;code&gt;ctx7 library&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 library react
ctx7 library nextjs &lt;span class="s2"&gt;"app router setup"&lt;/span&gt;
ctx7 library prisma &lt;span class="s2"&gt;"database relations"&lt;/span&gt;
ctx7 library express &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command returns the library's canonical ID and metadata, including snippet count, source reputation, benchmark scores, and version identifiers.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Library: /vercel/next.js
Snippets: 4,820
Reputation: high
Version: 15.2.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fetch documentation
&lt;/h3&gt;

&lt;p&gt;Pass the canonical library ID to &lt;code&gt;ctx7 docs&lt;/code&gt; with a topic query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 docs /facebook/react &lt;span class="s2"&gt;"useEffect cleanup"&lt;/span&gt;
ctx7 docs /vercel/next.js &lt;span class="s2"&gt;"middleware authentication"&lt;/span&gt;
ctx7 docs /prisma/prisma &lt;span class="s2"&gt;"one-to-many relations"&lt;/span&gt;
ctx7 docs /facebook/react &lt;span class="s2"&gt;"hooks"&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command returns documentation snippets relevant to your query from the current indexed version.&lt;/p&gt;

&lt;p&gt;If you already know the library ID, skip the search step and call &lt;code&gt;ctx7 docs&lt;/code&gt; directly.&lt;/p&gt;

&lt;p&gt;You can also pipe the output into a file or another command for further processing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 docs /facebook/react &lt;span class="s2"&gt;"hooks"&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; react-hooks.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Manage AI coding skills
&lt;/h2&gt;

&lt;p&gt;Skills are &lt;code&gt;SKILL.md&lt;/code&gt; files that give an AI agent specialized knowledge or behavior. Think of them as instruction manuals for a particular task or library.&lt;/p&gt;

&lt;p&gt;Context7 provides a registry of community-contributed skills. You can search for skills, install them, generate custom skills, and remove installed skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Search for skills
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 skills search pdf
ctx7 skills search &lt;span class="s2"&gt;"stripe payments"&lt;/span&gt;
ctx7 skills search &lt;span class="s2"&gt;"react testing"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install a skill
&lt;/h3&gt;

&lt;p&gt;Install a skill for your current environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 skills &lt;span class="nb"&gt;install&lt;/span&gt; /anthropics/skills pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Target a specific agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 skills &lt;span class="nb"&gt;install&lt;/span&gt; /anthropics/skills pdf &lt;span class="nt"&gt;--cursor&lt;/span&gt;
ctx7 skills &lt;span class="nb"&gt;install&lt;/span&gt; /anthropics/skills pdf &lt;span class="nt"&gt;--claude&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make the skill available across all projects, install it globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 skills &lt;span class="nb"&gt;install&lt;/span&gt; /anthropics/skills pdf &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get skill suggestions for a project
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;suggest&lt;/code&gt; command scans your project directory, detects the libraries and frameworks you're using, and recommends relevant skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 skills suggest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when starting a project and building an initial set of agent instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  List installed skills
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 skills list              &lt;span class="c"&gt;# List all installed skills&lt;/span&gt;
ctx7 skills list &lt;span class="nt"&gt;--claude&lt;/span&gt;     &lt;span class="c"&gt;# List Claude Code skills&lt;/span&gt;
ctx7 skills list &lt;span class="nt"&gt;--cursor&lt;/span&gt;     &lt;span class="c"&gt;# List Cursor skills&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove a skill
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 skills remove pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generate a custom skill
&lt;/h3&gt;

&lt;p&gt;With a paid account, you can generate a custom skill from a library in the Context7 index:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ctx7 login
ctx7 skills generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI walks you through an interactive prompt where you select a library and describe what you want the skill to teach your agent. Context7 then generates a &lt;code&gt;SKILL.md&lt;/code&gt; file based on the library's current documentation.&lt;/p&gt;

&lt;p&gt;Generated skills are portable. The &lt;code&gt;SKILL.md&lt;/code&gt; format follows the Agent Skills standard, so a skill generated for Claude Code can also work in Cursor, VS Code Copilot, OpenCode, and other Agent Skills-compatible tools.&lt;/p&gt;

&lt;p&gt;Free accounts include 6 skill generations per week. Pro accounts include 10.&lt;/p&gt;

&lt;h4&gt;
  
  
  Command aliases
&lt;/h4&gt;

&lt;p&gt;Use these aliases for shorter commands:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Full command&lt;/th&gt;
&lt;th&gt;Alias&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctx7 skills install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ctx7 si&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctx7 skills search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ctx7 ss&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ctx7 skills generate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ctx7 skills gen&lt;/code&gt; or &lt;code&gt;ctx7 skills g&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Use Context7 in AI prompts
&lt;/h2&gt;

&lt;p&gt;After setting up Context7, you can use it in several ways during development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use the &lt;code&gt;use context7&lt;/code&gt; pattern
&lt;/h3&gt;

&lt;p&gt;In MCP mode, append &lt;code&gt;use context7&lt;/code&gt; to prompts where you need current documentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create a Next.js middleware that checks for a valid JWT in cookies and redirects
unauthenticated users to /login. use context7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Set up a Prisma schema with user and post models and a one-to-many relation. use context7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;How do I configure the App Router layout in Next.js 15? use context7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls Context7's &lt;code&gt;resolve-library-id&lt;/code&gt; and &lt;code&gt;query-docs&lt;/code&gt; tools, fetches the relevant documentation, and uses it to ground the response.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference a specific library
&lt;/h3&gt;

&lt;p&gt;When a prompt involves multiple libraries, specify the library IDs explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Implement Supabase authentication in a Next.js app.

Use library /supabase/supabase for Supabase and /vercel/next.js for
Next.js routing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This skips the library-matching step and sends the request directly to the specified documentation sources.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatically invoke Context7
&lt;/h3&gt;

&lt;p&gt;You can add an instruction to your AI agent so it fetches documentation automatically whenever it generates code that uses a third-party library.&lt;/p&gt;

&lt;p&gt;For Claude Code, add this to &lt;code&gt;CLAUDE.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Always use Context7 MCP tools when generating code that uses third-party libraries.
Resolve the library ID and fetch current docs before writing any implementation.
Do this without waiting for me to ask.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Cursor, add the equivalent rule under &lt;strong&gt;Settings &amp;gt; Rules for AI&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When writing code that uses external libraries or frameworks, always invoke
Context7 to fetch current documentation before generating the implementation.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pair Context7 with Apidog for API confidence
&lt;/h2&gt;

&lt;p&gt;Context7 keeps your AI assistant's library knowledge current, but current documentation is only part of an API integration workflow. You also need to verify that the HTTP requests and responses behave as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?ref=apidog.com" rel="noopener noreferrer"&gt;Apidog&lt;/a&gt; is a free API client for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sending requests&lt;/li&gt;
&lt;li&gt;Inspecting responses&lt;/li&gt;
&lt;li&gt;Managing environments&lt;/li&gt;
&lt;li&gt;Storing API keys as variables&lt;/li&gt;
&lt;li&gt;Running repeatable test suites&lt;/li&gt;
&lt;li&gt;Adding response assertions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A practical workflow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use Context7 to give your AI agent current documentation for the framework or SDK.&lt;/li&gt;
&lt;li&gt;Use Apidog to call the third-party API directly.&lt;/li&gt;
&lt;li&gt;Inspect the response structure and status codes.&lt;/li&gt;
&lt;li&gt;Compare the tested request with the payload your application generates.&lt;/li&gt;
&lt;li&gt;Add repeatable tests for the integration.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, when building a Next.js application that calls a third-party API, Context7 can provide current Next.js documentation so the generated code uses the correct APIs. Apidog lets you test the third-party endpoint directly, verify the response structure, and confirm that your payload matches the API's expectations.&lt;/p&gt;

&lt;p&gt;The same approach works when integrating a library with its own HTTP API. Use Context7 to look up the current SDK documentation, then use Apidog to test the raw endpoints and understand their behavior before writing application code.&lt;/p&gt;

&lt;p&gt;When debugging an integration, send the exact request your application constructs in Apidog. Inspect the raw response to determine whether the issue is in your request logic or in the API's behavior.&lt;/p&gt;

&lt;p&gt;You can also create Apidog environments with API keys stored as variables, switch between development and production values, and run assertions against every response. Context7 provides current documentation, while Apidog helps verify actual API behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing and rate limits
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ctx7&lt;/code&gt; CLI is free to use. Rate limits and feature access depend on your Context7 plan:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;API calls/month&lt;/th&gt;
&lt;th&gt;Rate limit&lt;/th&gt;
&lt;th&gt;Private repositories&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;$0&lt;/td&gt;
&lt;td&gt;1,000&lt;/td&gt;
&lt;td&gt;60 requests/hour&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;$7/seat/month&lt;/td&gt;
&lt;td&gt;5,000/seat&lt;/td&gt;
&lt;td&gt;60/hour/seat&lt;/td&gt;
&lt;td&gt;Yes ($15/1M tokens to parse)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Enterprise&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;5,000/seat&lt;/td&gt;
&lt;td&gt;Custom&lt;/td&gt;
&lt;td&gt;Yes ($25/1M tokens)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Free-tier notes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;After reaching the monthly limit, you receive 20 bonus API calls per day until the month resets.&lt;/li&gt;
&lt;li&gt;Private repository access requires Pro or higher.&lt;/li&gt;
&lt;li&gt;Skill generation includes 6 generations per week on Free and 10 per week on Pro.&lt;/li&gt;
&lt;li&gt;Pro supports a maximum of 20 members.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One important limitation is that Context7 routes queries through Upstash's servers. It does not provide an offline mode, so it won't work in an environment without internet access.&lt;/p&gt;

&lt;p&gt;Documentation responses can also be large and consume part of your LLM's context window. On complex projects with many library queries, this usage can add up.&lt;/p&gt;

&lt;p&gt;Get a free API key at &lt;code&gt;context7.com/dashboard&lt;/code&gt;. An API key provides higher rate limits than unauthenticated requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Context7 send my code to its servers?
&lt;/h3&gt;

&lt;p&gt;No. Only the library name and query text are sent to Context7's servers. Your code, conversation history, and sensitive data are not sent. Your codebase remains with your LLM provider.&lt;/p&gt;

&lt;h3&gt;
  
  
  What libraries does Context7 support?
&lt;/h3&gt;

&lt;p&gt;The index covers more than 9,000 public libraries and frameworks. Search the index at &lt;code&gt;context7.com&lt;/code&gt; to check whether a library is available. New libraries can be submitted through &lt;code&gt;/add-library&lt;/code&gt; in the Context7 interface.&lt;/p&gt;

&lt;h3&gt;
  
  
  How current is the documentation?
&lt;/h3&gt;

&lt;p&gt;Libraries are re-indexed periodically. Very recent releases, including releases from the past few days, may not be available yet. For stable libraries, the documentation is typically up to date with the latest release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does it work without an API key?
&lt;/h3&gt;

&lt;p&gt;Basic usage works without an API key, but with lower rate limits. For regular use, register at &lt;code&gt;context7.com&lt;/code&gt; and set &lt;code&gt;CONTEXT7_API_KEY&lt;/code&gt; for higher throughput.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which editors and agents does it support?
&lt;/h3&gt;

&lt;p&gt;Context7 works with Claude Code, Cursor, OpenCode, VS Code Copilot, Windsurf, Claude Desktop, and other clients that support MCP or the Agent Skills standard.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the difference between CLI + Skills mode and MCP mode?
&lt;/h3&gt;

&lt;p&gt;In CLI + Skills mode, a skill file tells your agent to run &lt;code&gt;ctx7&lt;/code&gt; commands explicitly when it needs documentation.&lt;/p&gt;

&lt;p&gt;In MCP mode, your agent calls Context7's tools natively through the MCP protocol. MCP mode is more transparent and does not require an explicit &lt;code&gt;use context7&lt;/code&gt; prompt once configured.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use &lt;code&gt;ctx7&lt;/code&gt; without an AI coding agent?
&lt;/h3&gt;

&lt;p&gt;Yes. The &lt;code&gt;ctx7 library&lt;/code&gt; and &lt;code&gt;ctx7 docs&lt;/code&gt; commands work as standalone terminal tools, so you can look up library documentation without an AI coding agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Context7 GitHub repository&lt;/li&gt;
&lt;li&gt;Context7 documentation&lt;/li&gt;
&lt;li&gt;CLI documentation&lt;/li&gt;
&lt;li&gt;Plans and pricing&lt;/li&gt;
&lt;li&gt;API key dashboard&lt;/li&gt;
&lt;li&gt;Apidog free API client&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How Can You Install Firecrawl CLI and Use Firecrawl CLI</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Thu, 27 Aug 2026 13:01:24 +0000</pubDate>
      <link>https://dev.to/preecha/how-can-you-install-firecrawl-cli-and-use-firecrawl-cli-2alc</link>
      <guid>https://dev.to/preecha/how-can-you-install-firecrawl-cli-and-use-firecrawl-cli-2alc</guid>
      <description>&lt;h1&gt;
  
  
  Firecrawl CLI: A Practical Guide to Scraping, Searching, Crawling, and Browser Automation
&lt;/h1&gt;

&lt;p&gt;Firecrawl CLI is a terminal-native tool for AI agents and developers. It can scrape, search, map, crawl, and automate browser sessions while saving clean Markdown, JSON, screenshots, and HTML directly to your filesystem. Run it with &lt;code&gt;npx firecrawl-cli&lt;/code&gt; without a permanent installation, or install it globally and connect it to Claude Code, Cursor, or OpenCode with a single initialization command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;AI agents need reliable, current web data, but custom scrapers often break on JavaScript-rendered pages, dynamic sites, and protected flows. Firecrawl CLI combines web scraping, search, site mapping, recursive crawling, and cloud browser sessions in one tool.&lt;/p&gt;

&lt;p&gt;The CLI writes results to local files instead of sending large payloads directly to your terminal. That makes it easy to search output with standard shell tools, keep LLM context focused, and build repeatable research pipelines.&lt;/p&gt;

&lt;p&gt;This guide covers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preparing your environment&lt;/li&gt;
&lt;li&gt;Installing and authenticating Firecrawl CLI&lt;/li&gt;
&lt;li&gt;Scraping pages and selecting output formats&lt;/li&gt;
&lt;li&gt;Searching and mapping websites&lt;/li&gt;
&lt;li&gt;Crawling sites recursively&lt;/li&gt;
&lt;li&gt;Automating browser sessions&lt;/li&gt;
&lt;li&gt;Integrating with AI coding agents&lt;/li&gt;
&lt;li&gt;Troubleshooting and operational best practices&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Why Use Firecrawl CLI?
&lt;/h2&gt;

&lt;p&gt;Firecrawl CLI renders JavaScript through cloud browsers and is designed for sites that basic HTTP clients, Cheerio-based scrapers, or simple Puppeteer scripts may not handle reliably. It returns LLM-friendly Markdown by default, removing much of the navigation, advertising, and boilerplate content that consumes context-window space.&lt;/p&gt;

&lt;p&gt;The CLI supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web scraping&lt;/li&gt;
&lt;li&gt;Web search with optional result scraping&lt;/li&gt;
&lt;li&gt;URL discovery through site maps&lt;/li&gt;
&lt;li&gt;Recursive site crawling&lt;/li&gt;
&lt;li&gt;Screenshots and full-page screenshots&lt;/li&gt;
&lt;li&gt;Cloud browser sessions&lt;/li&gt;
&lt;li&gt;Markdown, JSON, HTML, links, and image outputs&lt;/li&gt;
&lt;li&gt;Local file output for shell scripts and agent workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, adding &lt;code&gt;--only-main-content&lt;/code&gt; to a scrape can significantly reduce irrelevant output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--only-main-content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prepare Your Environment
&lt;/h2&gt;

&lt;p&gt;Firecrawl CLI depends on modern Node.js and npm features. Verify that Node.js 18 or later is installed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the version is too old, update Node.js with your package manager or with &lt;a href="https://github.com/nvm-sh/nvm" rel="noopener noreferrer"&gt;nvm&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a dedicated workspace for output files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;firecrawl-cli-projects
&lt;span class="nb"&gt;cd &lt;/span&gt;firecrawl-cli-projects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A separate directory keeps generated datasets organized and makes them easy to track with Git.&lt;/p&gt;

&lt;p&gt;If you do not want telemetry enabled, set the environment variable before running the CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FIRECRAWL_NO_TELEMETRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Install Firecrawl CLI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Initialize Firecrawl CLI for AI Agents
&lt;/h3&gt;

&lt;p&gt;The initialization command is the quickest way to install Firecrawl CLI, authenticate, and configure agent skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; firecrawl-cli@latest init &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--browser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command opens a browser for Firecrawl account login or signup, stores your API key, and configures compatible agent integrations. Restart your coding agent after initialization so it can detect the new capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Globally with npm
&lt;/h3&gt;

&lt;p&gt;For frequent use across multiple projects, install the CLI globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; firecrawl-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the installation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A global installation lets you run &lt;code&gt;firecrawl&lt;/code&gt; from any directory without the &lt;code&gt;npx&lt;/code&gt; startup overhead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authenticate and Inspect Configuration
&lt;/h2&gt;

&lt;p&gt;Authenticate with the browser-based login flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also provide an API key directly through an environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FIRECRAWL_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fc-your-key-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check authentication and account status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl &lt;span class="nt"&gt;--status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This displays the current authentication state and available account information, such as credits and concurrency limits.&lt;/p&gt;

&lt;p&gt;To inspect the complete local configuration, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl view-config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switch accounts by logging out and signing in again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl &lt;span class="nb"&gt;logout
&lt;/span&gt;firecrawl login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a local or self-hosted Firecrawl instance, specify a custom API URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl &lt;span class="nt"&gt;--api-url&lt;/span&gt; http://localhost:3002
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scrape a Web Page
&lt;/h2&gt;

&lt;p&gt;Extract the primary content from a page with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--only-main-content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, Firecrawl CLI returns clean Markdown. Save the result to a specific file with &lt;code&gt;-o&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--only-main-content&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; output.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using a named output file is useful when you want to process the result in a later shell step or commit it to a dataset repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request Multiple Formats
&lt;/h3&gt;

&lt;p&gt;You can request several representations in one operation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--format&lt;/span&gt; markdown,json,html,links,images &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--pretty&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when an agent needs readable content alongside structured metadata or when you want to inspect the page's links and images separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Capture Screenshots
&lt;/h3&gt;

&lt;p&gt;Capture a viewport screenshot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--screenshot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a full-page image, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--full-page-screenshot&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wait for Dynamic Content
&lt;/h3&gt;

&lt;p&gt;If a page loads content asynchronously, add a wait timer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--wait-for&lt;/span&gt; 5000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value is specified in milliseconds. Increase it when important content appears only after client-side rendering completes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Filter Page Content
&lt;/h3&gt;

&lt;p&gt;Limit extraction to relevant HTML elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://docs.example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--include-tags&lt;/span&gt; main,article &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exclude-tags&lt;/span&gt; nav,footer,script
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;--timing&lt;/code&gt; when diagnosing slow requests or comparing different extraction settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--only-main-content&lt;/span&gt; &lt;span class="nt"&gt;--timing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Search the Web
&lt;/h2&gt;

&lt;p&gt;Search for a topic and scrape the top results in one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl search &lt;span class="s2"&gt;"latest AI agent benchmarks"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scrape&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--limit&lt;/span&gt; 8 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scrape-formats&lt;/span&gt; markdown
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firecrawl CLI saves the search and scraped results locally. You can then inspect them with standard command-line tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 2
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"benchmark"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the research task, you can also filter by recency, location, or source type. Combine search with mapping and browser sessions when the initial results require deeper verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Map a Website
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;map&lt;/code&gt; to discover URLs before extracting content from a site:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl map https://example.com &lt;span class="nt"&gt;-o&lt;/span&gt; sitemap.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command returns a structured list of URLs and associated metadata. Filter the resulting list before sending selected URLs to &lt;code&gt;scrape&lt;/code&gt; or &lt;code&gt;crawl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A map-first workflow helps you understand a site's structure and keeps large extraction jobs focused on the pages you actually need.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crawl a Site Recursively
&lt;/h2&gt;

&lt;p&gt;Start a recursive crawl with progress reporting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl crawl https://example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--progress&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; crawl-output.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Firecrawl CLI follows internal links, extracts page content, and stores the results locally. For larger sites, configure limits such as crawl depth, maximum pages, and concurrency to control runtime and usage.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--progress&lt;/code&gt; option provides visibility into a running job, while &lt;code&gt;--wait&lt;/code&gt; keeps the command active until the crawl completes.&lt;/p&gt;

&lt;p&gt;A practical crawl workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl map https://example.com &lt;span class="nt"&gt;-o&lt;/span&gt; sitemap.json
&lt;span class="c"&gt;# Filter sitemap.json for the sections you need.&lt;/span&gt;
firecrawl crawl https://example.com &lt;span class="nt"&gt;--wait&lt;/span&gt; &lt;span class="nt"&gt;--progress&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; crawl-output.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with a small scope, validate the output, and then expand the crawl.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automate Browser Sessions
&lt;/h2&gt;

&lt;p&gt;Use cloud browser sessions for interactive pages and multi-step flows.&lt;/p&gt;

&lt;p&gt;Launch a session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl browser launch-session
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command returns a session ID. Use that ID for browser actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl browser execute &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"open https://news.ycombinator.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--session&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click an element:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl browser execute &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"click .titleline &amp;gt; a"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--session&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Extract the current page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl browser execute &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"scrape"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--session&lt;/span&gt; &amp;lt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Browser sessions support navigation, clicking, typing, and extraction after dynamic interactions. Close sessions when they are no longer needed so resources are released.&lt;/p&gt;

&lt;p&gt;This approach replaces a large amount of custom Puppeteer orchestration with simple, agent-readable commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Global Options
&lt;/h2&gt;

&lt;p&gt;Persist common settings with the &lt;code&gt;config&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl config &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--api-url&lt;/span&gt; https://your-custom-endpoint &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--concurrency&lt;/span&gt; 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also configure output preferences and headers where supported by your installation. Keep the API key in an environment variable or shell profile rather than hard-coding it in scripts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FIRECRAWL_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;fc-your-key-here
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before starting a large search or crawl, check account status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl &lt;span class="nt"&gt;--status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps you review available credits and concurrency limits before launching a long-running job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate Firecrawl CLI with AI Coding Agents
&lt;/h2&gt;

&lt;p&gt;Initialize the Firecrawl CLI skill for compatible agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; firecrawl-cli@latest init &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In CLI-and-skills mode, the agent runs Firecrawl commands explicitly when web data is needed. In MCP mode, the agent can call the configured tools directly.&lt;/p&gt;

&lt;p&gt;Because Firecrawl CLI stores results as local files, an agent can receive a file path and inspect only the relevant sections instead of loading an entire response into context. This keeps research workflows more predictable and reduces unnecessary prompt data.&lt;/p&gt;

&lt;p&gt;A simple agent-oriented workflow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl search &lt;span class="s2"&gt;"topic to research"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scrape&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--limit&lt;/span&gt; 5 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--scrape-formats&lt;/span&gt; markdown &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; research.json

&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="s2"&gt;"key phrase"&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact agent integration depends on the coding tool and its configuration, but the underlying workflow remains the same: fetch current data, save it locally, and pass focused files or excerpts to the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshoot Common Problems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Authentication Errors
&lt;/h3&gt;

&lt;p&gt;Run the login flow again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are switching accounts or keys, clear the existing credentials first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl &lt;span class="nb"&gt;logout
&lt;/span&gt;firecrawl login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rate Limits or Concurrency Errors
&lt;/h3&gt;

&lt;p&gt;Reduce concurrency in your configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl config &lt;span class="nt"&gt;--concurrency&lt;/span&gt; 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check account status and available limits before retrying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl &lt;span class="nt"&gt;--status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Missing Content on JavaScript-Heavy Pages
&lt;/h3&gt;

&lt;p&gt;Increase the wait time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--wait-for&lt;/span&gt; 10000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also try extracting only the primary content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--only-main-content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use timing information to compare different settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--wait-for&lt;/span&gt; 10000 &lt;span class="nt"&gt;--timing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Unexpected or Empty Output
&lt;/h3&gt;

&lt;p&gt;Test the page with a broader extraction first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="nt"&gt;--format&lt;/span&gt; markdown,json,html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add content filters after you understand the page structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;firecrawl scrape https://example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--include-tags&lt;/span&gt; main,article &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--exclude-tags&lt;/span&gt; nav,footer,script
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;p&gt;Follow these practices to keep Firecrawl CLI workflows efficient and reproducible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;--only-main-content&lt;/code&gt; when you need concise Markdown.&lt;/li&gt;
&lt;li&gt;Give output files descriptive names.&lt;/li&gt;
&lt;li&gt;Store results in a dedicated directory.&lt;/li&gt;
&lt;li&gt;Test a small set of pages before starting a full crawl.&lt;/li&gt;
&lt;li&gt;Use a &lt;code&gt;search → map → scrape&lt;/code&gt; workflow for focused research.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;crawl&lt;/code&gt; when you need broad internal-link coverage.&lt;/li&gt;
&lt;li&gt;Set concurrency deliberately for large jobs.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;--timing&lt;/code&gt; when diagnosing performance issues.&lt;/li&gt;
&lt;li&gt;Version-control output directories when reproducibility matters.&lt;/li&gt;
&lt;li&gt;Review credit usage regularly.&lt;/li&gt;
&lt;li&gt;Keep API keys in environment variables instead of source files.&lt;/li&gt;
&lt;li&gt;Close browser sessions after interactive work is complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test Firecrawl API Requests with Apidog
&lt;/h2&gt;

&lt;p&gt;Apidog can complement Firecrawl CLI when you need to inspect or validate API requests before automating them in a terminal workflow. Import Firecrawl endpoints such as scrape, search, and crawl into an Apidog collection, then use variables for the API key and other request parameters.&lt;/p&gt;

&lt;p&gt;This lets you inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request headers&lt;/li&gt;
&lt;li&gt;API key handling&lt;/li&gt;
&lt;li&gt;Custom parameters&lt;/li&gt;
&lt;li&gt;Response shapes&lt;/li&gt;
&lt;li&gt;Different extraction options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also mock responses and run automated tests before moving a request into a shell script or agent workflow. This is useful when debugging complex options or validating an integration independently from the CLI.&lt;/p&gt;

&lt;p&gt;Learn more at &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync"&gt;Apidog&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Firecrawl CLI provides a terminal-first workflow for scraping, searching, mapping, crawling, and browser automation. Its local file output makes results easy to inspect with shell tools, pass to AI coding agents, and preserve as reproducible datasets.&lt;/p&gt;

&lt;p&gt;Start with the initialization command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx &lt;span class="nt"&gt;-y&lt;/span&gt; firecrawl-cli@latest init &lt;span class="nt"&gt;--all&lt;/span&gt; &lt;span class="nt"&gt;--browser&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then authenticate, run a small scrape, and expand into search, mapping, crawling, or browser automation as your workflow requires. Careful use of format selectors, content filters, wait timers, and concurrency settings can improve both output quality and efficiency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.firecrawl.dev/sdks/cli" rel="noopener noreferrer"&gt;Firecrawl CLI documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.firecrawl.dev" rel="noopener noreferrer"&gt;Firecrawl main site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/firecrawl/cli" rel="noopener noreferrer"&gt;Firecrawl CLI GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.firecrawl.dev/api-reference" rel="noopener noreferrer"&gt;Firecrawl API reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://app.firecrawl.dev" rel="noopener noreferrer"&gt;Firecrawl dashboard and API key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync"&gt;Apidog free API client&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>How Can You and Use Google Workspace CLI</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Thu, 27 Aug 2026 02:01:50 +0000</pubDate>
      <link>https://dev.to/preecha/how-can-you-and-use-google-workspace-cli-1fm1</link>
      <guid>https://dev.to/preecha/how-can-you-and-use-google-workspace-cli-1fm1</guid>
      <description>&lt;h1&gt;
  
  
  Automate Google Workspace from the command line with &lt;code&gt;gws&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;Google Workspace CLI (&lt;code&gt;gws&lt;/code&gt;) is an open-source command-line tool that provides unified access to Drive, Gmail, Calendar, Sheets, Docs, Chat, Admin, and other Google Workspace APIs. It builds commands dynamically from Google’s Discovery Service, so you can automate Workspace tasks without maintaining separate SDKs, custom OAuth flows, or hand-written &lt;code&gt;curl&lt;/code&gt; scripts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use Google Workspace CLI?
&lt;/h2&gt;

&lt;p&gt;Automating Google Workspace often requires you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure OAuth scopes and credentials&lt;/li&gt;
&lt;li&gt;Learn separate APIs for each Workspace service&lt;/li&gt;
&lt;li&gt;Handle pagination manually&lt;/li&gt;
&lt;li&gt;Maintain multiple SDKs&lt;/li&gt;
&lt;li&gt;Update scripts when API methods change&lt;/li&gt;
&lt;li&gt;Define custom tools for AI agents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Google Workspace CLI provides a single, Rust-powered interface that discovers Workspace API methods at runtime. It was released in early 2026 by the Google team and announced by Addy Osmani.&lt;/p&gt;

&lt;p&gt;The CLI provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON output suitable for scripts and agents&lt;/li&gt;
&lt;li&gt;Dry-run support&lt;/li&gt;
&lt;li&gt;Pagination helpers&lt;/li&gt;
&lt;li&gt;Dynamically discovered API commands&lt;/li&gt;
&lt;li&gt;More than 40 task-oriented &lt;code&gt;+&lt;/code&gt; helpers, such as &lt;code&gt;gws gmail +send&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Agent skills for Claude Code, Cursor, OpenClaw, and Gemini CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you also need to inspect requests, debug OAuth scopes, or verify payloads, Apidog can handle the API testing side of the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install Google Workspace CLI
&lt;/h2&gt;

&lt;p&gt;Google Workspace CLI requires Node.js 18 or later.&lt;/p&gt;

&lt;p&gt;Check your installed version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run without installing
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;npx&lt;/code&gt; for a quick test or one-off script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @googleworkspace/cli &lt;span class="nt"&gt;--help&lt;/span&gt;
npx @googleworkspace/cli drive files list &lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="s1"&gt;'{"pageSize":1}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This downloads and runs the latest package without installing &lt;code&gt;gws&lt;/code&gt; globally.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install globally
&lt;/h3&gt;

&lt;p&gt;For regular use, install the package globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @googleworkspace/cli
gws &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The npm package includes prebuilt binaries, so you do not need to compile the Rust project locally.&lt;/p&gt;

&lt;p&gt;You can also install the CLI from GitHub Releases, with Homebrew, or through Nix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;googleworkspace/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configure authentication
&lt;/h2&gt;

&lt;p&gt;Run the guided setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws auth setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The setup flow opens a browser and handles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a Google Cloud project if needed&lt;/li&gt;
&lt;li&gt;Enabling the required Workspace APIs&lt;/li&gt;
&lt;li&gt;Completing the initial OAuth flow&lt;/li&gt;
&lt;li&gt;Saving credentials in your operating system’s keyring&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stored credentials are encrypted with AES-256-GCM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure only the current project
&lt;/h3&gt;

&lt;p&gt;By default, setup applies globally. To create project-specific configuration, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws auth setup &lt;span class="nt"&gt;--project&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check or change the authenticated account
&lt;/h3&gt;

&lt;p&gt;Log in or switch accounts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inspect the current user and granted scopes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws auth &lt;span class="nb"&gt;whoami&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Log out:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws auth &lt;span class="nb"&gt;logout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use Google Workspace CLI in CI or headless environments
&lt;/h2&gt;

&lt;p&gt;Export credentials to a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws auth &lt;span class="nb"&gt;export&lt;/span&gt; &lt;span class="nt"&gt;--unmasked&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; creds.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then point the CLI to that file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_WORKSPACE_CLI_CREDENTIALS_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/path/to/creds.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Treat the exported file as a secret. Do not commit it to source control.&lt;/p&gt;

&lt;p&gt;You can also reuse an access token from &lt;code&gt;gcloud&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_WORKSPACE_CLI_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gcloud auth print-access-token&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Disable telemetry
&lt;/h3&gt;

&lt;p&gt;To disable anonymous usage collection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_WORKSPACE_CLI_NO_TELEMETRY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Discover available commands
&lt;/h2&gt;

&lt;p&gt;Google Workspace CLI discovers commands dynamically rather than relying on a fixed command list.&lt;/p&gt;

&lt;p&gt;Start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then explore the available services and methods from the command line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work with Google Drive
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List files
&lt;/h3&gt;

&lt;p&gt;List up to 10 files whose names contain &lt;code&gt;report&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws drive files list &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="s1"&gt;'{"pageSize":10, "q":"name contains report"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the output is JSON, you can pipe it into tools such as &lt;code&gt;jq&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws drive files list &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="s1"&gt;'{"pageSize":10}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upload a file
&lt;/h3&gt;

&lt;p&gt;Use the &lt;code&gt;+upload&lt;/code&gt; helper to upload a local file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws drive +upload ./budget.xlsx &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"2026 Budget"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Work with Gmail
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Send an email
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws gmail +send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; colleague@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Update"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"See attached."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attach&lt;/span&gt; ./file.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Reply to a message
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws gmail +reply &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--message-id&lt;/span&gt; &amp;lt;ID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"Thanks!"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;ID&amp;gt;&lt;/code&gt; with the Gmail message ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  Triage the inbox
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws gmail +triage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Work with Google Calendar
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create an event
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws calendar +insert &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--summary&lt;/span&gt; &lt;span class="s2"&gt;"Sprint Planning"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--start&lt;/span&gt; &lt;span class="s2"&gt;"2026-03-20T10:00"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--end&lt;/span&gt; &lt;span class="s2"&gt;"2026-03-20T11:00"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--attendees&lt;/span&gt; &lt;span class="s2"&gt;"team@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show today’s agenda
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws calendar +agenda &lt;span class="nt"&gt;--today&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Work with Google Sheets
&lt;/h2&gt;

&lt;p&gt;Append a row to a spreadsheet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws sheets +append &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--spreadsheetId&lt;/span&gt; &amp;lt;ID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--range&lt;/span&gt; &lt;span class="s2"&gt;"Sheet1!A:C"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--values&lt;/span&gt; &lt;span class="s2"&gt;"Task X,Done,2026-03-16"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;ID&amp;gt;&lt;/code&gt; with the spreadsheet ID from the Google Sheets URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work with Google Docs
&lt;/h2&gt;

&lt;p&gt;Insert text into a document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws docs +write &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--documentId&lt;/span&gt; &amp;lt;ID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"New section added via Google Workspace CLI"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;ID&amp;gt;&lt;/code&gt; with the document ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work with Google Chat
&lt;/h2&gt;

&lt;p&gt;Post a message to a Chat space:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws chat +send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--space&lt;/span&gt; &amp;lt;SPACE_ID&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--text&lt;/span&gt; &lt;span class="s2"&gt;"Deployment complete 🚀"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;&amp;lt;SPACE_ID&amp;gt;&lt;/code&gt; with the target Chat space ID.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preview commands before executing them
&lt;/h2&gt;

&lt;p&gt;Add &lt;code&gt;--dry-run&lt;/code&gt; to preview the API call without executing it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws gmail +send &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--to&lt;/span&gt; colleague@example.com &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subject&lt;/span&gt; &lt;span class="s2"&gt;"Update"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--body&lt;/span&gt; &lt;span class="s2"&gt;"See attached."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--dry-run&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Testing commands generated by an AI agent&lt;/li&gt;
&lt;li&gt;Checking parameters before modifying Workspace data&lt;/li&gt;
&lt;li&gt;Debugging request payloads&lt;/li&gt;
&lt;li&gt;Reviewing automation in CI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Handle pagination
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;--page-all&lt;/code&gt; to retrieve all pages as newline-delimited JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws drive files list &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="s1"&gt;'{"pageSize":100}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--page-all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NDJSON output is convenient for streaming and processing large result sets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure default behavior
&lt;/h2&gt;

&lt;p&gt;Persist default parameters with an environment variable or a &lt;code&gt;.env&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;GOOGLE_WORKSPACE_CLI_DEFAULT_PARAMS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{"prettyPrint":true}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CLI also supports output options such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws drive files list &lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="s1"&gt;'{"pageSize":10}'&lt;/span&gt; &lt;span class="nt"&gt;--json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws drive files list &lt;span class="nt"&gt;--params&lt;/span&gt; &lt;span class="s1"&gt;'{"pageSize":10}'&lt;/span&gt; &lt;span class="nt"&gt;--yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also adjust timeouts or force file-based keyring storage.&lt;/p&gt;

&lt;p&gt;View the current configuration with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connect Google Workspace CLI to an AI coding agent
&lt;/h2&gt;

&lt;p&gt;After authentication, install the bundled agent skills:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add https://github.com/googleworkspace/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also use an agent-specific installer for tools such as Claude Code or Cursor. Restart the agent afterward so it can discover the installed skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt the agent to use &lt;code&gt;gws&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Be explicit in your prompts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;List my recent Drive files using Google Workspace CLI.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Send a follow-up email via Google Workspace CLI.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Show today's Calendar agenda with gws, then summarize the meetings.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add an automatic invocation rule
&lt;/h3&gt;

&lt;p&gt;Add a rule like the following to &lt;code&gt;CLAUDE.md&lt;/code&gt;, Cursor rules, or your agent’s instruction file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Whenever a task involves Gmail, Drive, Calendar, Sheets, Docs, or Chat,
use Google Workspace CLI commands before responding. Resolve the service
and method first.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets the agent use &lt;code&gt;gws&lt;/code&gt; for Workspace operations and return file paths or JSON results without loading unnecessary data into its context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify Workspace API calls with Apidog
&lt;/h2&gt;

&lt;p&gt;Google Workspace CLI executes Workspace operations from the terminal. When you need to inspect a raw payload or troubleshoot authentication, use Apidog to reproduce and validate the underlying API request.&lt;/p&gt;

&lt;p&gt;Practical workflows include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test a &lt;code&gt;Sheets.values.append&lt;/code&gt; payload before an agent writes to a spreadsheet&lt;/li&gt;
&lt;li&gt;Inspect Gmail send requests while debugging OAuth scopes&lt;/li&gt;
&lt;li&gt;Store user tokens or service-account credentials as environment variables&lt;/li&gt;
&lt;li&gt;Switch between accounts and compare responses&lt;/li&gt;
&lt;li&gt;Add assertions for repeatable API checks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A useful workflow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build or preview the command with &lt;code&gt;gws --dry-run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Reproduce the request in Apidog.&lt;/li&gt;
&lt;li&gt;Inspect the URL, headers, body, and response.&lt;/li&gt;
&lt;li&gt;Confirm the required OAuth scopes.&lt;/li&gt;
&lt;li&gt;Run the final &lt;code&gt;gws&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Save the API request as a repeatable test when appropriate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Google Workspace CLI provides live Workspace access, while Apidog provides a visual environment for request inspection and repeatable API testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does Google Workspace CLI send my data externally?
&lt;/h3&gt;

&lt;p&gt;No. Calls go directly to Google APIs, and your content remains in your Google account.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which services does Google Workspace CLI support?
&lt;/h3&gt;

&lt;p&gt;It supports Workspace APIs discovered dynamically, including Drive, Gmail, Calendar, Sheets, Docs, Chat, Admin, and Script.&lt;/p&gt;

&lt;h3&gt;
  
  
  How current are the commands?
&lt;/h3&gt;

&lt;p&gt;Google Workspace CLI queries Google’s live Discovery Service, so newly exposed methods can appear without waiting for a CLI update.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does it require an API key?
&lt;/h3&gt;

&lt;p&gt;It uses standard Google OAuth or service-account authentication. You do not need a separate API key beyond the required authentication credentials.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which agents and editors does it support?
&lt;/h3&gt;

&lt;p&gt;Google Workspace CLI can be used with Claude Code, Cursor, OpenClaw, Gemini CLI, VS Code extensions, and tools compatible with MCP or Agent Skills.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the difference between raw commands and &lt;code&gt;+&lt;/code&gt; helpers?
&lt;/h3&gt;

&lt;p&gt;Raw commands map to Discovery API methods, such as &lt;code&gt;drive.files.list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Commands prefixed with &lt;code&gt;+&lt;/code&gt; are shortcuts for common tasks, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gws drive +upload
gws gmail +send
gws calendar +agenda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Can I use Google Workspace CLI without an AI agent?
&lt;/h3&gt;

&lt;p&gt;Yes. You can use it directly for shell scripts, CI jobs, scheduled automation, and day-to-day terminal tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Google Workspace CLI GitHub repository → &lt;a href="https://github.com/googleworkspace/cli" rel="noopener noreferrer"&gt;https://github.com/googleworkspace/cli&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Full README and documentation → &lt;a href="https://github.com/googleworkspace/cli/blob/main/README.md" rel="noopener noreferrer"&gt;https://github.com/googleworkspace/cli/blob/main/README.md&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Agent skills folder → &lt;a href="https://github.com/googleworkspace/cli/tree/main/skills" rel="noopener noreferrer"&gt;https://github.com/googleworkspace/cli/tree/main/skills&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Google Workspace API reference → &lt;a href="https://developers.google.com/workspace" rel="noopener noreferrer"&gt;https://developers.google.com/workspace&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Quotas dashboard → &lt;a href="https://console.cloud.google.com/apis/api" rel="noopener noreferrer"&gt;https://console.cloud.google.com/apis/api&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Apidog free API client → &lt;a href="https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync"&gt;https://apidog.com?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=blog-sync&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>api</category>
      <category>automation</category>
      <category>cli</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Impeccable: The Claude Code Skill for Unique Frontend UI</title>
      <dc:creator>Preecha</dc:creator>
      <pubDate>Thu, 27 Aug 2026 01:01:14 +0000</pubDate>
      <link>https://dev.to/preecha/impeccable-the-claude-code-skill-for-unique-frontend-ui-316p</link>
      <guid>https://dev.to/preecha/impeccable-the-claude-code-skill-for-unique-frontend-ui-316p</guid>
      <description>&lt;p&gt;Impeccable is an open-source Claude Code skill created by Paul Bakaus to reduce generic, AI-generated frontend output. It includes 20 steering commands—including &lt;code&gt;/audit&lt;/code&gt;, &lt;code&gt;/polish&lt;/code&gt;, and &lt;code&gt;/critique&lt;/code&gt;—seven domain-specific design references, and curated anti-patterns that tell the model what not to generate. The goal is straightforward: build interfaces that look intentionally designed rather than auto-generated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apidog.com/?utm_source=dev.to&amp;amp;utm_medium=wanda&amp;amp;utm_content=n8n-post-automation" class="crayons-btn crayons-btn--primary"&gt;Try Apidog today&lt;/a&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI-Generated Frontends Often Look the Same
&lt;/h2&gt;

&lt;p&gt;Ask an AI coding assistant to build a dashboard, landing page, or settings panel without additional direction. The result often includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inter or another default sans-serif font&lt;/li&gt;
&lt;li&gt;A purple-to-blue gradient&lt;/li&gt;
&lt;li&gt;Cards nested inside other cards&lt;/li&gt;
&lt;li&gt;Gray text on colored backgrounds&lt;/li&gt;
&lt;li&gt;Centered hero sections with a large number and small label&lt;/li&gt;
&lt;li&gt;Glassmorphism used as a default depth effect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These patterns are functional, but they are also predictable. Large language models learn from the same common templates, so their frontend output tends to converge on the same visual language.&lt;/p&gt;

&lt;p&gt;Impeccable is designed to interrupt that pattern. Anthropic's official &lt;code&gt;frontend-design&lt;/code&gt; skill provides a foundation; Impeccable extends it with deeper design guidance, broader domain coverage, and explicit constraints that steer the model away from recurring AI-generated UI patterns.&lt;/p&gt;

&lt;p&gt;If you plan to use &lt;code&gt;/audit&lt;/code&gt;, &lt;code&gt;/polish&lt;/code&gt;, or &lt;code&gt;/overdrive&lt;/code&gt; in Claude Code, you can also use &lt;a href="https://apidog.com/?ref=apidog.com" rel="noopener noreferrer"&gt;Apidog&lt;/a&gt; to validate the API endpoints your frontend depends on. Check request payloads, authentication tokens, response shapes, and mock data before UI and backend integration issues create extra rework.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Impeccable Includes
&lt;/h2&gt;

&lt;p&gt;Impeccable is an installable Claude Code skill made up of instructions, reference files, and slash commands. It augments how Claude Code approaches frontend implementation and review.&lt;/p&gt;

&lt;p&gt;The skill has three core parts.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Expanded &lt;code&gt;frontend-design&lt;/code&gt; Skill
&lt;/h3&gt;

&lt;p&gt;Impeccable's frontend guidance is divided into seven domain-specific reference files:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxod4t6tidv5ro9yl3yqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxod4t6tidv5ro9yl3yqv.png" alt="Image" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each reference is intended to be used during implementation, not just read as general advice. For example, the typography reference covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vertical rhythm&lt;/li&gt;
&lt;li&gt;Font loading and Flash of Unstyled Text (FOUT)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;size-adjust&lt;/code&gt; overrides&lt;/li&gt;
&lt;li&gt;Appropriate and inappropriate uses of fluid typography with &lt;code&gt;clamp()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This level of detail gives the model concrete decisions to apply while generating or revising frontend code.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Context-Gathering Protocol
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;/teach-impeccable&lt;/code&gt; command collects project-specific design context before design work begins. It asks you to define details such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Target audience&lt;/li&gt;
&lt;li&gt;Primary use cases&lt;/li&gt;
&lt;li&gt;Brand personality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The answers are saved to &lt;code&gt;.impeccable.md&lt;/code&gt; in the project root and loaded in future sessions.&lt;/p&gt;

&lt;p&gt;This step matters because a model without project context defaults to safe, average choices. Establishing the context once gives later commands a more specific design direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 20 Commands for Improving AI-Generated Frontends
&lt;/h2&gt;

&lt;p&gt;Run Impeccable commands as slash commands inside Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/audit              → Accessibility, performance, and responsive quality check
/critique           → UX review covering hierarchy, clarity, and emotional resonance
/polish             → Final pass for alignment, spacing, and implementation details
/distill            → Remove complexity that does not earn its place
/normalize           → Align the interface with design-system standards
/animate            → Add purposeful motion
/colorize           → Introduce strategic color to a monochromatic interface
/bolder             → Push a safe or overly conservative design further
/quieter             → Tone down an overly aggressive design
/delight             → Add memorable moments of interaction
/typeset             → Improve font choices, hierarchy, and sizing
/arrange             → Fix layout, spacing, and visual rhythm
/harden             → Address error handling, internationalization, and edge cases
/optimize            → Improve frontend performance
/extract             → Pull out reusable components and design tokens
/adapt               → Adapt the interface for other devices or contexts
/onboard             → Design onboarding flows and empty states
/clarify              → Improve unclear UX copy
/overdrive           → Add technically ambitious effects
/teach-impeccable    → Save project-specific design context
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Most commands accept an optional scope. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/audit header
/polish checkout-form
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first command limits the audit to the navigation bar. The second focuses the polish pass on the checkout form. Scoped commands reduce the chance of changing frontend areas that already work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chain Commands for a Repeatable Review
&lt;/h3&gt;

&lt;p&gt;A practical workflow is to run commands in sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/audit
/arrange
/typeset
/polish
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each step addresses a different category of problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;/audit&lt;/code&gt; identifies accessibility, performance, and responsive issues.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/arrange&lt;/code&gt; corrects layout and spacing.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/typeset&lt;/code&gt; improves the type hierarchy.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/polish&lt;/code&gt; performs the final visual pass before shipping.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Use Anti-Patterns to Prevent Generic UI
&lt;/h2&gt;

&lt;p&gt;Impeccable's anti-pattern library is one of its most distinctive features. Instead of offering only broad style preferences, it names recurring failure modes and turns them into explicit constraints.&lt;/p&gt;

&lt;h3&gt;
  
  
  Typography Anti-Patterns
&lt;/h3&gt;

&lt;p&gt;Avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inter, Roboto, Arial, or system defaults when they make the design indistinguishable from common templates&lt;/li&gt;
&lt;li&gt;Monospace fonts used only to imply “developer vibes”&lt;/li&gt;
&lt;li&gt;Large rounded icons above every heading, which creates a repeated template structure&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Color Anti-Patterns
&lt;/h3&gt;

&lt;p&gt;Avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gray text on colored backgrounds; use a darker shade of the background color when appropriate&lt;/li&gt;
&lt;li&gt;The familiar AI palette of cyan on dark backgrounds, purple-to-blue gradients, and neon accents&lt;/li&gt;
&lt;li&gt;Pure black (&lt;code&gt;#000&lt;/code&gt;) and pure white (&lt;code&gt;#fff&lt;/code&gt;); tint neutral colors instead&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Layout Anti-Patterns
&lt;/h3&gt;

&lt;p&gt;Avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrapping every element in a card&lt;/li&gt;
&lt;li&gt;Nesting cards inside cards&lt;/li&gt;
&lt;li&gt;Repeating identical icon-heading-text card grids&lt;/li&gt;
&lt;li&gt;Centering every element when a left-aligned or asymmetric layout would create stronger hierarchy&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Motion Anti-Patterns
&lt;/h3&gt;

&lt;p&gt;Avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bounce and elastic easing that makes interactions feel dated&lt;/li&gt;
&lt;li&gt;Animating layout properties such as &lt;code&gt;width&lt;/code&gt;, &lt;code&gt;height&lt;/code&gt;, or &lt;code&gt;padding&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prefer &lt;code&gt;transform&lt;/code&gt; and &lt;code&gt;opacity&lt;/code&gt; for motion where possible. This reduces layout work and generally produces smoother transitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build System, Tests, and Tool Support
&lt;/h2&gt;

&lt;p&gt;Impeccable is maintained as a software project rather than a collection of prompt files. It includes a build system, unit tests, and support for multiple AI development tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build Provider-Specific Bundles
&lt;/h3&gt;

&lt;p&gt;Source skill files are stored in &lt;code&gt;source/skills/&lt;/code&gt; and use YAML frontmatter based on the Agent Skills specification.&lt;/p&gt;

&lt;p&gt;Build the provider bundles with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To remove existing output and rebuild everything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun run rebuild
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The build system compiles the source into formats for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cursor&lt;/li&gt;
&lt;li&gt;Claude Code&lt;/li&gt;
&lt;li&gt;OpenCode&lt;/li&gt;
&lt;li&gt;Gemini CLI&lt;/li&gt;
&lt;li&gt;Codex CLI&lt;/li&gt;
&lt;li&gt;VS Code Copilot&lt;/li&gt;
&lt;li&gt;Kiro&lt;/li&gt;
&lt;li&gt;Pi&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each provider receives the metadata format it expects. For example, Claude Code and OpenCode include metadata such as arguments and allowed tools, while Codex CLI uses argument hints with &lt;code&gt;$ARGNAME&lt;/code&gt; placeholders. Gemini receives minimal frontmatter.&lt;/p&gt;

&lt;p&gt;The transformations are implemented through the modular architecture in &lt;code&gt;scripts/lib/transformers/&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the Unit Test Suite
&lt;/h3&gt;

&lt;p&gt;The Bun-based test suite is located in &lt;code&gt;tests/build.test.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tests cover the complete build pipeline, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orchestration and transformer arguments&lt;/li&gt;
&lt;li&gt;Integration tests that create source files in a temporary directory&lt;/li&gt;
&lt;li&gt;Output-file existence for every supported provider&lt;/li&gt;
&lt;li&gt;Provider-specific transformations&lt;/li&gt;
&lt;li&gt;Empty skill-list edge cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The transformation tests also verify provider-specific output, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;{{args}}&lt;/code&gt; in Gemini output&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$TARGET&lt;/code&gt; in Codex output&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user-invokable: true&lt;/code&gt; in Claude Code output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you modify a transformer, run &lt;code&gt;bun test&lt;/code&gt; before contributing. This provides quick feedback across all supported tool formats.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pair Impeccable with Apidog for API-Driven Frontends
&lt;/h2&gt;

&lt;p&gt;Impeccable focuses on the UI layer. Apidog focuses on the API layer.&lt;/p&gt;

&lt;p&gt;A polished frontend can still fail users when its API calls are undocumented, untested, or unreliable. Apidog helps validate the backend contract that the generated interface depends on.&lt;/p&gt;

&lt;p&gt;With Apidog, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Design APIs visually before implementing the backend&lt;/li&gt;
&lt;li&gt;Generate mock servers from an API schema&lt;/li&gt;
&lt;li&gt;Render realistic data in an AI-generated frontend during development&lt;/li&gt;
&lt;li&gt;Run automated endpoint tests and catch regressions&lt;/li&gt;
&lt;li&gt;Share interactive API documentation with the team&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The division of responsibility is useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Impeccable to make the interface distinctive, accessible, and production-ready.&lt;/li&gt;
&lt;li&gt;Use Apidog to validate the requests, responses, mocks, and documentation behind that interface.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, they address two common weaknesses in AI-assisted development: generic visual output and unreliable integration behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started with Impeccable
&lt;/h2&gt;

&lt;p&gt;Download the ready-to-use bundle from &lt;code&gt;impeccable.style&lt;/code&gt;, choose your target tool, and extract it into the appropriate location.&lt;/p&gt;

&lt;p&gt;For Claude Code, install at the project level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; dist/claude-code/.claude your-project/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or install globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; dist/claude-code/.claude/&lt;span class="k"&gt;*&lt;/span&gt; ~/.claude/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the setup command once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/teach-impeccable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the design context is saved, you can use the remaining commands in the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  How is Impeccable different from Anthropic's official &lt;code&gt;frontend-design&lt;/code&gt; skill?
&lt;/h3&gt;

&lt;p&gt;Impeccable builds on that foundation with seven domain-specific reference files, 20 steering commands, and an explicit anti-pattern library. The official skill is a starting point; Impeccable adds a broader system for guiding and reviewing frontend output.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Impeccable support tools other than Claude Code?
&lt;/h3&gt;

&lt;p&gt;Yes. It supports Cursor, Claude Code, OpenCode, Gemini CLI, Codex CLI, VS Code Copilot, Kiro, and Pi. Its build system compiles one source format into provider-specific dialects.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does &lt;code&gt;/overdrive&lt;/code&gt; do?
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;/overdrive&lt;/code&gt; is intended for technically ambitious effects such as WebGL shaders, 60fps virtual tables, spring physics in dialogs, and scroll-driven reveals. Use it when the design calls for effects beyond conventional frontend patterns.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does Impeccable handle unit testing?
&lt;/h3&gt;

&lt;p&gt;The project includes a Bun-based suite covering the build pipeline, transformer correctness, and integration tests that generate real source files and verify provider outputs.&lt;/p&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bun &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Can Impeccable help with API-driven frontends?
&lt;/h3&gt;

&lt;p&gt;Impeccable handles UI quality. For the API layer, pair it with Apidog for visual API design, automated testing, and mock server generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Impeccable free to use?
&lt;/h3&gt;

&lt;p&gt;Yes. Impeccable is open source under the Apache 2.0 license. Its source code is available on GitHub, and compiled bundles are available at &lt;code&gt;impeccable.style&lt;/code&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
