<?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: Anup Karanjkar</title>
    <description>The latest articles on DEV Community by Anup Karanjkar (@akaranjkar08).</description>
    <link>https://dev.to/akaranjkar08</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%2F235395%2Fca502edd-b701-43c6-8324-7b07fefe0f24.jpg</url>
      <title>DEV Community: Anup Karanjkar</title>
      <link>https://dev.to/akaranjkar08</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/akaranjkar08"/>
    <language>en</language>
    <item>
      <title>Sandbox Claude Code and Codex 2026: Docker, gVisor, microVM</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Fri, 16 Oct 2026 09:21:24 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/sandbox-claude-code-and-codex-2026-docker-gvisor-microvm-26i</link>
      <guid>https://dev.to/akaranjkar08/sandbox-claude-code-and-codex-2026-docker-gvisor-microvm-26i</guid>
      <description>&lt;p&gt;&lt;strong&gt;For one developer running Claude Code or Codex CLI unattended, a hardened Docker container with default-deny egress covers most of the real risk, and gVisor or a microVM only pays off when you run code you do not control.&lt;/strong&gt; Docker shares the host kernel, gVisor swaps it for a user-space kernel written in Go, and a microVM such as Firecracker gives each workload its own guest kernel behind KVM. The part people skip is egress: a perfectly isolated container that can reach any host still leaks every file it can read. Both Anthropic and OpenAI say the same thing in their docs, and both tell you to put the permission-bypass flags inside an isolation boundary. Below: the threat model, what the bypass flags remove, one comparison table, a hardened &lt;code&gt;docker run&lt;/code&gt;, a compose egress proxy, &lt;code&gt;runsc&lt;/code&gt; registration, and the microVM entry points.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The threat is a prompt-injected shell that reads credentials and sends them out. Kernel escapes are the rarer problem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;--dangerously-skip-permissions&lt;/code&gt; (Claude Code) and &lt;code&gt;--yolo&lt;/code&gt; (Codex) remove the prompts. Neither adds isolation, so the container has to.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docker hardening (non-root, read-only rootfs, &lt;code&gt;--cap-drop ALL&lt;/code&gt;, &lt;code&gt;no-new-privileges&lt;/code&gt;, egress allowlist) gets you most of the way.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;gVisor: add it when you want a smaller host-kernel surface and your toolchain survives its syscall gaps. 62 of 352 syscalls are unsupported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;microVM: add it for multi-tenant agents, CI runners, or untrusted repos. Firecracker advertises under 125 ms boot and under 5 MiB overhead per VM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On macOS 26 with Apple silicon, Apple's &lt;code&gt;container&lt;/code&gt; tool runs Linux containers as lightweight VMs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The threat model for an unattended coding agent
&lt;/h2&gt;

&lt;p&gt;An agent that runs for an hour with no human watching has four realistic failure paths, in the order they bite:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Prompt-injected shell.&lt;/strong&gt; A README, issue, web page or dependency postinstall script contains instructions. The model follows them and runs &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;npm publish&lt;/code&gt; with your tokens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Exfiltration over egress.&lt;/strong&gt; Anything the process can read leaves through any open port. Isolation does not help if the network is open.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Credential files in $HOME.&lt;/strong&gt; &lt;code&gt;~/.ssh&lt;/code&gt;, &lt;code&gt;~/.aws&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt; files and the agent's own login token. Anthropic's dev container page warns that with the skip flag a malicious project can exfiltrate anything reachable inside the container, including the credentials in &lt;code&gt;~/.claude&lt;/code&gt;[2]. OpenAI's Codex docs say the same about Codex credentials[3].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Docker socket mounts.&lt;/strong&gt; Mounting &lt;code&gt;/var/run/docker.sock&lt;/code&gt; hands the agent the daemon. Docker's security page warns that API access can lead to privilege escalation and shows a bind mount of &lt;code&gt;/&lt;/code&gt; as the example[5]. A container with the socket is not a sandbox.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A kernel exploit comes fifth. It matters for multi-tenant hosting, where the attacker is another customer. For a solo developer on a trusted repo it is the least likely path, which is why a hardened container often suffices.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the bypass flags actually remove
&lt;/h2&gt;

&lt;p&gt;Both flags remove approval prompts and, in Codex's case, the sandbox too. They are not isolation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Claude Code:&lt;/strong&gt; with &lt;code&gt;--dangerously-skip-permissions&lt;/code&gt;, Claude acts without asking. Anthropic says to always run these sessions inside a container, a VM, or the sandbox runtime. The CLI refuses to start with the flag as root[1]. Admins can block it with &lt;code&gt;permissions.disableBypassPermissionsMode&lt;/code&gt; set to &lt;code&gt;"disable"&lt;/code&gt; in managed settings[2].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Codex CLI:&lt;/strong&gt; &lt;code&gt;--dangerously-bypass-approvals-and-sandbox&lt;/code&gt;, alias &lt;code&gt;--yolo&lt;/code&gt;, means no sandbox and no approvals, flagged "not recommended". The default preset is &lt;code&gt;--sandbox workspace-write --ask-for-approval on-request&lt;/code&gt;, with network off unless you set &lt;code&gt;network_access = true&lt;/code&gt; under &lt;code&gt;[sandbox_workspace_write]&lt;/code&gt;[3].&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both vendors ship their own host-level sandboxes. Claude Code's built-in Bash sandbox is off by default, enabled with &lt;code&gt;/sandbox&lt;/code&gt;, built on the open-source &lt;code&gt;@anthropic-ai/sandbox-runtime&lt;/code&gt;, and uses Seatbelt on macOS and bubblewrap plus socat on Linux. It covers shell commands only. File tools, MCP servers and hooks run outside it, so Anthropic says it is not sufficient for fully unattended runs[1][4]. Codex uses Seatbelt on macOS and bwrap plus seccomp on Linux[3]. These are useful layers. For unattended work, put the whole process in a container or VM and let the built-in sandbox run inside it. Anthropic notes unprivileged containers need &lt;code&gt;enableWeakerNestedSandbox&lt;/code&gt; for that[4]. For the hosted-agent angle, see &lt;a href="https://dev.to/blogs/claude-managed-agents-self-hosted-sandbox-mcp-tunnels-enterprise-guide-2026"&gt;Claude Managed Agents self-hosted sandbox&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comparison: Docker vs gVisor vs microVM vs Apple container
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;What is isolated&lt;/th&gt;
&lt;th&gt;Kernel&lt;/th&gt;
&lt;th&gt;Startup&lt;/th&gt;
&lt;th&gt;OS support&lt;/th&gt;
&lt;th&gt;Performance cost&lt;/th&gt;
&lt;th&gt;Egress control&lt;/th&gt;
&lt;th&gt;Setup effort&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Docker (runc), hardened | Namespaces, cgroups, capabilities, seccomp (default profile blocks around 44 of 300+ syscalls) | Shared host kernel | No VM boot | Linux native; elsewhere via a Linux VM | Near zero | Your job: internal network plus proxy allowlist | Low | Free |&lt;/p&gt;

&lt;p&gt;| gVisor (&lt;code&gt;runsc&lt;/code&gt;) | Syscalls handled by the Sentry, a Go user-space kernel | User-space kernel; host kernel sees far fewer calls | Small fixed per-sandbox cost, no numbers published | Linux hosts (install guide is Linux-only) | Low for CPU-bound work; high for syscall-heavy or small-file workloads | Netstack by default; &lt;code&gt;--network=none&lt;/code&gt;; experimental proxy mode | Low to medium | Free, open source |&lt;/p&gt;

&lt;p&gt;| Firecracker microVM | Whole guest OS behind KVM | Separate guest kernel | Under 125 ms boot (vendor claim) | Linux x86_64 and aarch64 with /dev/kvm | Under 5 MiB overhead per VM (vendor claim) | Guest NIC, you filter at host or tap device | High (kernel, rootfs, networking) | Free, open source |&lt;/p&gt;

&lt;p&gt;| Kata Containers | Pod or container inside a lightweight VM | Separate guest kernel | Not stated in README | Linux with virtualization support | VM overhead, hypervisor-dependent | Kubernetes network policy on top | Medium to high | Free, open source |&lt;/p&gt;

&lt;p&gt;| Apple &lt;code&gt;container&lt;/code&gt; | Linux containers as lightweight VMs | Separate guest kernel | Not published in README | macOS 26, Apple silicon only | VM overhead, no GPU claim made | No documented allowlist feature; use a proxy | Low | Free, Apache-2.0 |&lt;/p&gt;

&lt;p&gt;| Docker Sandboxes | MicroVM with its own Docker daemon and workspace sync | Separate guest kernel | Not stated | Per Anthropic: any host with it installed | VM overhead | Network policies in its Security guide | Low | Free standalone product per Anthropic; admin policy is a paid tier |&lt;/p&gt;

&lt;h2&gt;
  
  
  Docker hardening that gets you most of the way
&lt;/h2&gt;

&lt;p&gt;This is the baseline. Every flag below is documented in Docker's &lt;code&gt;docker run&lt;/code&gt; reference[6]. Run the container as a non-root user, because Claude Code requires that for the skip flag anyway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--user&lt;/span&gt; 1000:1000 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--read-only&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tmpfs&lt;/span&gt; /tmp:rw,noexec,nosuid,size&lt;span class="o"&gt;=&lt;/span&gt;512m &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--tmpfs&lt;/span&gt; /home/agent/.cache:rw,nosuid,size&lt;span class="o"&gt;=&lt;/span&gt;1g &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--cap-drop&lt;/span&gt; ALL &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--security-opt&lt;/span&gt; no-new-privileges &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--pids-limit&lt;/span&gt; 512 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--memory&lt;/span&gt; 4g &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--network&lt;/span&gt; agent_net &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;HTTPS_PROXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://proxy:3128 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;HTTP_PROXY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http://proxy:3128 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$PWD&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;:/work &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-w&lt;/span&gt; /work &lt;span class="se"&gt;\&lt;/span&gt;
  my-agent-image claude
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What each line buys you: &lt;code&gt;--read-only&lt;/code&gt; stops the agent persisting malware or editing system files. &lt;code&gt;--cap-drop ALL&lt;/code&gt; removes every Linux capability; Docker's default is already an allowlist, and dropping all is stricter[5]. &lt;code&gt;no-new-privileges&lt;/code&gt; blocks setuid escalation. The default seccomp profile stays on unless you disable it, and you can swap in your own with &lt;code&gt;--security-opt seccomp=/path/profile.json&lt;/code&gt;[7]. Mount only the project directory. Never mount &lt;code&gt;~/.ssh&lt;/code&gt;, cloud credential files or the Docker socket. Pass a repo-scoped, short-lived token as an environment variable instead.&lt;/p&gt;

&lt;p&gt;The remaining gap is the network. Put the agent on an internal network with no route out, and attach a proxy to both that network and a normal one:&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;agent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-agent-image&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1000:1000"&lt;/span&gt;
    &lt;span class="na"&gt;read_only&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;cap_drop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ALL&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;security_opt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no-new-privileges:true"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;pids_limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;512&lt;/span&gt;
    &lt;span class="na"&gt;mem_limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;4g&lt;/span&gt;
    &lt;span class="na"&gt;tmpfs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/tmp:rw,noexec,nosuid,size=512m"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;HTTPS_PROXY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://proxy:3128&lt;/span&gt;
      &lt;span class="na"&gt;HTTP_PROXY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://proxy:3128&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;./:/work"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;working_dir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/work&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;agent_net&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu/squid&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./squid.conf:/etc/squid/squid.conf:ro&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./allowed-domains.txt:/etc/squid/allowed-domains.txt:ro&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;agent_net&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;egress&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;agent_net&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;internal&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;egress&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;code&gt;squid.conf&lt;/code&gt;, the allowlist is three lines: &lt;code&gt;acl allowed dstdomain "/etc/squid/allowed-domains.txt"&lt;/code&gt;, &lt;code&gt;http_access allow allowed&lt;/code&gt;, &lt;code&gt;http_access deny all&lt;/code&gt;. Start the domain file with &lt;code&gt;api.anthropic.com&lt;/code&gt; or &lt;code&gt;api.openai.com&lt;/code&gt;, plus your package registry, and add hosts only when a build fails and you agree it should succeed. Anthropic's dev container uses the same default-deny idea through an iptables script, and says the skip flag should be paired with egress restrictions[2]. If you would rather not assemble and test this yourself, the &lt;a href="https://dev.to/product/agent-sandbox-kit"&gt;WOWHOW Agent Sandbox Kit&lt;/a&gt; ($29) ships the hardened Docker config, a Squid default-deny allowlist and a smoke test that proves the egress rules hold.&lt;/p&gt;

&lt;p&gt;The catch: proxy variables only constrain tools that honor them. &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;npm&lt;/code&gt; and &lt;code&gt;git&lt;/code&gt; over HTTPS do. Raw TCP clients do not, but on an &lt;code&gt;internal: true&lt;/code&gt; network they have no route anyway, which is why the internal network does the real enforcement and the proxy only supplies the exception list.&lt;/p&gt;

&lt;h2&gt;
  
  
  When gVisor (runsc) is worth it
&lt;/h2&gt;

&lt;p&gt;gVisor is an application kernel. Its Sentry implements the Linux interface in Go and, per the docs, does not pass system calls through to the host kernel. A Gofer process mediates file access[8]. The host kernel sees a handful of calls from the Sentry instead of everything the agent's processes issue, so a kernel bug reachable from a syscall is harder to hit. It runs as an OCI runtime, so Docker treats it as a drop-in. Register 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;sudo&lt;/span&gt; /usr/local/bin/runsc &lt;span class="nb"&gt;install
sudo &lt;/span&gt;systemctl reload docker
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;--runtime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;runsc hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;runsc install&lt;/code&gt; edits Docker's runtime configuration for you[9]. Install the binary first using gVisor's tarball or apt package. After that, add &lt;code&gt;--runtime=runsc&lt;/code&gt; to the hardened &lt;code&gt;docker run&lt;/code&gt; above. For no network at all, runsc accepts &lt;code&gt;--network=none&lt;/code&gt;, which leaves only a loopback[11].&lt;/p&gt;

&lt;p&gt;The price is compatibility and speed. gVisor's compatibility table for amd64 covers 352 syscalls: 290 implemented fully or partly, 62 not at all. Unimplemented examples include &lt;code&gt;userfaultfd&lt;/code&gt;, &lt;code&gt;perf_event_open&lt;/code&gt; (returns no such device), &lt;code&gt;io_uring_register&lt;/code&gt; and &lt;code&gt;vmsplice&lt;/code&gt;. io_uring and ptrace are only partly supported[10]. For an agent that runs &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;pytest&lt;/code&gt; and &lt;code&gt;git&lt;/code&gt;, this rarely bites. It bites profilers, debuggers using perf, and anything built on io_uring. On performance, gVisor's own page says CPU-bound work runs natively while syscall-heavy and small-file, VFS-heavy workloads pay the most, and it recommends the Systrap platform for best performance[12]. A big &lt;code&gt;node_modules&lt;/code&gt; install is exactly the file-heavy case, so time it before you commit.&lt;/p&gt;

&lt;h2&gt;
  
  
  When a microVM is justified
&lt;/h2&gt;

&lt;p&gt;A microVM gives the workload its own kernel. A guest kernel exploit lands inside the VM, and the attacker still needs a hypervisor escape. Anthropic's sandbox page makes the same call: a dedicated VM is the strongest separation and fits untrusted code or policy that demands kernel-level separation[4]. Justify it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Several customers or teams share one host (multi-tenant agents).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You run CI runners that execute pull-request code from strangers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You build a Codex-cloud-style service where each task gets a fresh machine.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Firecracker needs read/write access to &lt;code&gt;/dev/kvm&lt;/code&gt; on x86_64 or aarch64 Linux and advertises boot under 125 ms and under 5 MiB overhead per VM[13]. The one-liner, from its getting-started guide, boots from a JSON config holding the kernel and rootfs:&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;sudo&lt;/span&gt; ./firecracker &lt;span class="nt"&gt;--api-sock&lt;/span&gt; /tmp/firecracker.socket &lt;span class="nt"&gt;--config-file&lt;/span&gt; vm-config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Building the kernel image, rootfs and tap networking is a project of its own[14]. Kata Containers wraps a lightweight VM behind a containerd shimv2 runtime so Kubernetes can schedule it like a pod, and &lt;code&gt;kata-runtime check&lt;/code&gt; tests whether a host can run it[15]. Follow the Kata install guide for the runtime-class registration rather than copying a snippet from memory. For a single developer who wants VM isolation without the assembly, Docker Sandboxes (a microVM with its own Docker daemon) is the lower-effort route Anthropic points to[4].&lt;/p&gt;

&lt;h2&gt;
  
  
  Apple container on macOS 26
&lt;/h2&gt;

&lt;p&gt;Apple's open-source &lt;code&gt;container&lt;/code&gt; tool runs Linux containers as lightweight virtual machines on a Mac. It needs Apple silicon, supports macOS 26 only, is Apache-2.0, and builds on the Containerization Swift package. Install the signed package from the GitHub releases page, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;container system start
container run --rm alpine echo hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The README says the project is under active development, release versions are product versions rather than semantic versions, and experimental features may change[16].&lt;/p&gt;

&lt;h2&gt;
  
  
  Which one to pick
&lt;/h2&gt;

&lt;p&gt;Solo developer, trusted repo, Linux or Mac: hardened Docker plus the egress proxy, then the vendor's built-in sandbox inside it. Running agents you cannot supervise on code you did not write: add &lt;code&gt;--runtime=runsc&lt;/code&gt; if your toolchain passes a smoke run, or move to a microVM. Selling agent runs to other people: microVM, no debate. Whichever you choose, cap the money side too, since a contained agent can still burn tokens. See &lt;a href="https://dev.to/blogs/claude-code-spend-limit-hard-caps-codex-runaway-bill-2026"&gt;Claude Code spend limits and Codex runaway bills&lt;/a&gt;, price a run with the &lt;a href="https://dev.to/tools/agent-run-cost-simulator"&gt;agent run cost simulator&lt;/a&gt;, and check that the Codex daemon is not leaving state behind in &lt;a href="https://dev.to/blogs/codex-cli-daemon-background-process-disk-usage-how-to-turn-off-2026"&gt;this disk usage guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is --dangerously-skip-permissions safe inside Docker?
&lt;/h3&gt;

&lt;p&gt;Safer, not safe. The container limits file and process damage, but Anthropic warns a malicious project can still exfiltrate anything reachable inside it, including Claude credentials. Add egress restrictions, avoid mounting host secrets, and use a non-root user, which the flag requires.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Docker isolate the kernel?
&lt;/h3&gt;

&lt;p&gt;No. Containers share the host kernel and rely on namespaces, cgroups, capabilities and seccomp. That is enough against a misbehaving agent and not enough against a determined attacker with a kernel exploit, which is the gap gVisor and microVMs close.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is gVisor or a microVM stronger?
&lt;/h3&gt;

&lt;p&gt;A microVM, in general, because the boundary is a hypervisor and a separate guest kernel. gVisor shrinks the host kernel surface but still runs on the host kernel. gVisor is easier to adopt because it plugs into Docker as &lt;code&gt;--runtime=runsc&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  What does Codex do by default for network access?
&lt;/h3&gt;

&lt;p&gt;It is off. The default preset runs &lt;code&gt;workspace-write&lt;/code&gt; with network disabled, and you enable it with &lt;code&gt;network_access = true&lt;/code&gt; under &lt;code&gt;[sandbox_workspace_write]&lt;/code&gt;. Using &lt;code&gt;--yolo&lt;/code&gt; removes the sandbox entirely, so put it inside a container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Apple container to sandbox agents on a Mac?
&lt;/h3&gt;

&lt;p&gt;Yes, on Apple silicon with macOS 26. It runs each Linux container as a lightweight VM. It is under active development, so pin the version and test before relying on it for anything unattended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/sandboxing" rel="noopener noreferrer"&gt;Claude Code: configure the sandboxed Bash tool (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/devcontainer" rel="noopener noreferrer"&gt;Claude Code: development containers (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://learn.chatgpt.com/docs/agent-approvals-security" rel="noopener noreferrer"&gt;OpenAI Codex: agent approvals and security (formerly developers.openai.com/codex, accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/sandbox-environments" rel="noopener noreferrer"&gt;Claude Code: choose a sandbox environment (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.docker.com/engine/security/" rel="noopener noreferrer"&gt;Docker Engine security (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.docker.com/reference/cli/docker/container/run/" rel="noopener noreferrer"&gt;docker container run reference (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.docker.com/engine/security/seccomp/" rel="noopener noreferrer"&gt;Docker seccomp security profiles (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gvisor.dev/docs/" rel="noopener noreferrer"&gt;gVisor documentation (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gvisor.dev/docs/user_guide/install/" rel="noopener noreferrer"&gt;gVisor installation (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gvisor.dev/docs/user_guide/compatibility/linux/amd64/" rel="noopener noreferrer"&gt;gVisor Linux amd64 syscall compatibility (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gvisor.dev/docs/user_guide/networking/" rel="noopener noreferrer"&gt;gVisor networking (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gvisor.dev/docs/architecture_guide/performance/" rel="noopener noreferrer"&gt;gVisor performance guide (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://firecracker-microvm.github.io/" rel="noopener noreferrer"&gt;Firecracker project site (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/firecracker-microvm/firecracker/blob/main/docs/getting-started.md" rel="noopener noreferrer"&gt;Firecracker getting started (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/kata-containers/kata-containers" rel="noopener noreferrer"&gt;Kata Containers repository (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/apple/container" rel="noopener noreferrer"&gt;Apple container repository (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Every product mentioned is available at wowhow.cloud — pay once, ship forever.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/sandbox-claude-code-codex-docker-vs-gvisor-vs-microvm-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sandboxclaude</category>
      <category>codexcli</category>
      <category>dangerouslyskip</category>
      <category>gvisorvs</category>
    </item>
    <item>
      <title>Diwali Gifts 2026: Income Tax, GST and TDS Rules in India</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Fri, 16 Oct 2026 07:32:44 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/diwali-gifts-2026-income-tax-gst-and-tds-rules-in-india-3il0</link>
      <guid>https://dev.to/akaranjkar08/diwali-gifts-2026-income-tax-gst-and-tds-rules-in-india-3il0</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Employee gifts, vouchers and tokens carry nil perquisite value only if the year's total is below ₹15,000 (up from ₹5,000) under the Income-tax Rules 2026. Cash never qualifies. GST treats employer gifts up to ₹50,000 per employee per year as no supply, and the input credit on those gifts is blocked. Client and dealer gifts above ₹20,000 a year trigger 10% TDS under section 194R of the 1961 Act, now section 393(1) of the 2025 Act. Recipients who are not employees pay tax on gifts above ₹50,000 from non-relatives. Dhanteras gold is 3% GST. Deposit November TDS by 7 December.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Diwali gift rulebook changed this year, and the biggest change is a number most employers still quote wrong.&lt;/strong&gt; The employee gift limit is ₹15,000, not ₹5,000, from 1 April 2026[1]. Diwali is on Sunday 8 November and Dhanteras on Friday 6 November 2026, so every hamper you ship lands in the first festival season under the Income-tax Act 2025. This post covers employee gifts, GST and blocked credit, TDS on client gifts, what recipients owe, gold, cash limits and the Diwali bonus. It ends with a worked example for a 40-employee company and a dated checklist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This article is for informational purposes only and does not constitute financial, tax, or legal advice. Consult a qualified professional for advice specific to your situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rules at a glance
&lt;/h2&gt;

&lt;p&gt;Start with the matrix. Every row is explained below with its source.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Who gives&lt;/th&gt;
&lt;th&gt;Who receives&lt;/th&gt;
&lt;th&gt;Tax head&lt;/th&gt;
&lt;th&gt;Threshold&lt;/th&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Employer, non-cash gift, voucher or token | Employee | Salary (perquisite) | Nil value if aggregate is below ₹15,000 in the tax year | Income-tax Rules 2026, Rule 15; earlier Rule 3(7)(iv) |&lt;/p&gt;

&lt;p&gt;| Employer, cash gift or bonus | Employee | Salary | No exemption at any amount | Salary provisions, 1961 Act s.17; 2025 Act s.16 and s.17 per mapping tables |&lt;/p&gt;

&lt;p&gt;| Employer (GST) | Employee | Not a supply up to ₹50,000 a financial year | ₹50,000 per employee | CGST Act Schedule I, item 2 proviso |&lt;/p&gt;

&lt;p&gt;| Business | Client, dealer, vendor | TDS on benefit, 10% | Aggregate above ₹20,000 a financial year | s.194R, 1961 Act; s.393(1), 2025 Act |&lt;/p&gt;

&lt;p&gt;| Any non-relative | Any person (not employee) | Income from other sources | Money or property above ₹50,000 aggregate | s.56(2)(x), 1961 Act; s.92(2)(m), 2025 Act |&lt;/p&gt;

&lt;p&gt;| Any person | Business taking cash | Penalty on receiver | ₹2 lakh or more in one day, transaction or event | s.269ST, 1961 Act |&lt;/p&gt;

&lt;p&gt;| Employer, statutory bonus | Employee earning up to ₹21,000 a month | Salary | 8.33% minimum, 20% maximum of capped wages | Code on Wages 2019, s.26 |&lt;/p&gt;

&lt;h2&gt;
  
  
  Which law applies: the 1961 Act or the 2025 Act
&lt;/h2&gt;

&lt;p&gt;The Income-tax Act 2025 applies from 1 April 2026, so Diwali 2026 sits inside tax year 2026-27[1]. Section numbers changed. Here is what I could confirm and how confident I am.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Salary TDS:&lt;/strong&gt; old s.192 is now s.392. The department's Form 123 FAQ says Form 123 replaces Form 12BA, the perquisites statement, under s.392(5)(a) and Rule 204(2) of the Income-tax Rules 2026[3].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Section 194R:&lt;/strong&gt; one commercial TDS site maps it to s.393(1), table serial 8(iv), return form 26Q[4]. I found no official page repeating that, so check the table before you file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Income from other sources:&lt;/strong&gt; old s.56 is now s.92[5]. A section-by-section copy of s.92 places the old 56(2)(x) gift rule at s.92(2)(m), with exceptions in s.92(3)[6]. That is a secondary source too.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Perquisites:&lt;/strong&gt; the Form 123 FAQ names s.17(1)(h) and (i) of the 2025 Act as the perquisite provisions[3]. A secondary mapping table says the salary definition moves to s.16[5].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Section 269ST and the 271DA penalty:&lt;/strong&gt; I could not verify the new numbers, so this post uses the 1961 numbering for both.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Per the sources I could reach, the substance of each rule below is unchanged except the employee gift limit. Quote both section numbers until your CA confirms the table.&lt;/p&gt;

&lt;h2&gt;
  
  
  Employee gifts: the ₹15,000 rule
&lt;/h2&gt;

&lt;p&gt;Under Rule 3(7)(iv) of the Income-tax Rules 1962, gifts, vouchers and tokens given by an employer were valued at nil if the aggregate stayed below ₹5,000 in the year. The Income-tax Rules 2026, notified on 20 March 2026 after a draft in February, raise that to ₹15,000[1]. The rule text is Rule 15(5)(a), Table IV, item 4 of the Income-tax Rules 2026: the value is "the sum equal to the amount of such gift", and nil only if the value of the gift, voucher or token is "below Rs. 15,000 in aggregate during the tax year"[18].&lt;/p&gt;

&lt;p&gt;The plan flagged ₹15,000 as an unexplained figure. This is it.&lt;/p&gt;

&lt;h3&gt;
  
  
  How to apply the limit
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One bucket for the year.&lt;/strong&gt; The limit is per employee per tax year across every gift: Diwali hamper, birthday voucher, service award. Tax year 2026-27 runs 1 April 2026 to 31 March 2027, so gifts since April count.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cash gets nothing.&lt;/strong&gt; Cash gifts, gift cheques and the Diwali "bonus in an envelope" are salary in full[7].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross the line and plan for the whole amount.&lt;/strong&gt; The rule values gifts at their full amount and gives nil only when the aggregate is below ₹15,000. The rule text says "below", so ₹15,000 exactly is already fully taxable. Stay under it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vouchers.&lt;/strong&gt; Closed-loop store vouchers fit the rule. Reloadable or cash-convertible cards risk being treated as cash, so ask the issuer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Above the limit, the gift is a perquisite and enters salary TDS under s.392, with the value reported to the employee on Form 123.&lt;/p&gt;

&lt;h2&gt;
  
  
  GST on employee gifts and the credit trap
&lt;/h2&gt;

&lt;p&gt;Schedule I, item 2 of the CGST Act treats supplies between related persons as supplies even without payment, when made in the course of business. Employer and employee are related persons. The proviso then says gifts "not exceeding fifty thousand rupees in value in a financial year by an employer to an employee shall not be treated as supply"[8].&lt;/p&gt;

&lt;p&gt;CBIC said the same in a July 2017 press release: gifts up to ₹50,000 a year are outside GST, while gifts above that made without consideration "are subject to GST" when made in the course of business[9]. The wording points to GST on the whole value once you cross the line. "Gift" is undefined; the release calls it voluntary, occasional and not demandable by the employee. A festival hamper fits. A fixed Diwali payment in the appointment letter does not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blocked credit under section 17(5)(h)
&lt;/h3&gt;

&lt;p&gt;Section 17(5)(h) blocks credit on goods "lost, stolen, destroyed, written off or disposed of by way of gift or free samples". CBIC's sales promotion circular 92/11/2019-GST applies it directly: ITC is not available on inputs used for gifts or free samples distributed without consideration. The one exception: where the distribution is a supply because of Schedule I, the supplier can take the credit[10].&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gift&lt;/th&gt;
&lt;th&gt;GST on the gift itself&lt;/th&gt;
&lt;th&gt;ITC on the purchase&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Hamper to an employee, within ₹50,000 a year | Not a supply | Blocked |&lt;/p&gt;

&lt;p&gt;| Gift to an employee above ₹50,000 a year | Supply, GST payable | Available, per circular 92/11/2019 para A(ii) |&lt;/p&gt;

&lt;p&gt;| Hamper to a client, dealer or vendor | Not a supply (no consideration, not related) | Blocked |&lt;/p&gt;

&lt;p&gt;| Voucher bought for staff | Voucher is neither goods nor services; underlying supply taxed on redemption | No GST charged at purchase |&lt;/p&gt;

&lt;p&gt;One caution. Circular 92/11/2019 remains in force, and Circular 251/08/2025 still refers to it. The circular withdrawn in 2019 was No. 105, a different one. The block stands on the statute text in any case, so claim nothing on gifts. The voucher row comes from circular 243/37/2024-GST[11].&lt;/p&gt;

&lt;p&gt;Where do the credit mistakes happen? In GSTR-2B. A hamper invoice from a sweet maker or gift vendor appears there as eligible credit, and the accounts clerk claims it. Pull gift invoices before the October 2026 GSTR-3B and reverse any you took. The &lt;a href="https://dev.to/blogs/gst-itc-deadline-30-november-2026-fy-2025-26-claim-guide"&gt;GST ITC deadline guide&lt;/a&gt; lists the other blocked credits and the 30 November cut-off. Check hamper rates with the &lt;a href="https://dev.to/tools/gst-rate-finder"&gt;GST rate finder&lt;/a&gt; and split the tax out with the &lt;a href="https://dev.to/tools/gst-calculator"&gt;GST calculator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gifts to clients, dealers and vendors: section 194R
&lt;/h2&gt;

&lt;p&gt;Since 1 July 2022, section 194R has required the person giving a benefit or perquisite arising from business or profession to a resident to deduct 10% when the value in a financial year goes above ₹20,000[2]. Circular 12/2022 of 16 June 2022 and circular 18/2022 of 13 September 2022 explain how it works[12][13].&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Answer&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Cash or kind? | Both. Free samples, cars, trips and event tickets are benefits | Circular 12/2022, Q2 and Q4 |&lt;/p&gt;

&lt;p&gt;| Valuation | Fair market value, or your purchase price if you bought it. GST is excluded | Circular 12/2022, Q5 |&lt;/p&gt;

&lt;p&gt;| Threshold | ₹20,000 per recipient per financial year; above it, tax applies to the whole value | s.194R proviso |&lt;/p&gt;

&lt;p&gt;| Who is exempt as giver | Individuals and HUFs with prior-year turnover up to ₹1 crore (business) or receipts up to ₹50 lakh (profession). Companies and firms get no turnover relief | Circulars 12/2022 and 18/2022 |&lt;/p&gt;

&lt;p&gt;| Gift in kind: how to pay | Make sure the tax is paid before you release the gift: take the client's advance tax challan, or deduct and pay it yourself. Report in Form 26Q | Circular 12/2022, Q9 |&lt;/p&gt;

&lt;p&gt;Small gifts add up. A distributor who got a ₹9,000 festival box in April, a ₹7,000 conference trip in July and a ₹6,000 Diwali hamper has crossed ₹20,000, and the whole ₹22,000 is in scope. Track benefits per recipient, not per occasion. Estimate the deduction with the &lt;a href="https://dev.to/tools/tds-calculator"&gt;TDS calculator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What recipients owe
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Employees
&lt;/h3&gt;

&lt;p&gt;Gifts from your employer are salary perquisites, not "income from other sources". The residual head applies only to income not chargeable under another head[6]. An employee's hamper is therefore taxed as a salary perquisite under Rule 15, not under the non-relative gift rule[18]. The ₹15,000 limit decides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Everyone else: section 56(2)(x) and section 92(2)(m)
&lt;/h3&gt;

&lt;p&gt;If you receive money from a non-relative and the total in the tax year exceeds ₹50,000, the whole sum is taxable. Movable "property" received for free is taxable if its aggregate fair market value exceeds ₹50,000. In the 2025 Act, "property" means listed capital assets such as shares, jewellery and bullion[6]. Immovable property uses stamp duty value, with the same ₹50,000 trigger.&lt;/p&gt;

&lt;p&gt;Main exceptions, not the full list[6]:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gifts from a relative&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gifts on the recipient's marriage&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gifts under a will or inheritance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gifts in contemplation of the donor's death&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Receipts from a local authority or a registered non-profit organisation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gifts from a HUF to its member, from specified funds or trusts, and on transfers exempt under s.47 of the 1961 Act[20]&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Diwali is not on that list. A ₹60,000 gold coin from a non-relative is taxable to you in full. From your brother it is not. Sweets and decor are not listed "property", so the rule rarely bites on hampers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dhanteras: gold, silver and cash limits
&lt;/h2&gt;

&lt;p&gt;Dhanteras is on 6 November. Gold carries 3% GST. CBIC's jewellery FAQ confirms 3% on the total transaction value of jewellery whether or not the making charge is shown separately[14]. The 2017 CBIC sectoral FAQ puts job work on jewellery at 5% of job charges; confirm against the current services rate notification, which was re-issued in September 2025. The September 2025 overhaul left jewellery (HSN 7113) and coin (HSN 7118) at 3% (CBIC Schedule V, 1.5% CGST + 1.5% SGST).&lt;/p&gt;

&lt;p&gt;Cash is the real limit. Section 269ST bars a person from receiving ₹2 lakh or more in cash from one person in a day, for one transaction, or for one event. The penalty falls on the receiver and equals the amount received[15]. A jeweller who accepts ₹2.4 lakh in notes for a Dhanteras coin faces a ₹2.4 lakh penalty. Use UPI or bank transfer for everything above those lines.&lt;/p&gt;

&lt;p&gt;A coin gifted to an employee will usually top ₹15,000, so plan for full perquisite tax and blocked credit on the 3% GST.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diwali bonus is not a gift
&lt;/h2&gt;

&lt;p&gt;A Diwali bonus is salary. It goes into the employee's taxable pay and attracts TDS under s.392 (old s.192) at the employee's slab, with no ₹15,000 shelter.&lt;/p&gt;

&lt;p&gt;The statutory bonus regime has moved. The Payment of Bonus Act 1965 is now run through Chapter IV of the Code on Wages 2019, in force from 21 November 2025. On 25 August 2026 the labour ministry notified two things for central-sphere establishments: employees earning up to ₹21,000 a month with at least 30 days' work in the year are eligible under s.26(1), and bonus is computed on wages of ₹7,000 or the minimum wage, whichever is higher. Both apply retrospectively from 21 November 2025[16]. The percentage bands are unchanged at a minimum of 8.33% and a maximum of 20%[17]. At the ₹7,000 base, 8.33% for twelve months is ₹6,997 and 20% is ₹16,800.&lt;/p&gt;

&lt;p&gt;Most SMEs fall under their state government, and the law firm notes that state notifications are expected, not yet issued. Check your state before you finalise the payout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: a 40-employee SME
&lt;/h2&gt;

&lt;p&gt;An illustrative company, taxed as a private limited company, buys gifts for Diwali 2026. All amounts are in rupees. GST at 18% on the gifts.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Amount (₹)&lt;/th&gt;
&lt;th&gt;Income tax outcome&lt;/th&gt;
&lt;th&gt;GST and ITC outcome&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| 40 employee hampers at ₹4,500 each, GST included | 1,80,000 | Nil perquisite, each employee below ₹15,000 | Not a supply. GST of ₹27,458 (180,000 × 18/118) paid to the vendor is blocked ITC |&lt;/p&gt;

&lt;p&gt;| One employee, Meera, also got an ₹11,000 voucher in July | 15,500 total (4,500 + 11,000) | Aggregate above ₹15,000, so the full ₹15,500 is perquisite. At a 30% slab plus 4% cess (31.2%) that is ₹4,836 of extra tax, deducted through salary TDS | Voucher: no GST at purchase |&lt;/p&gt;

&lt;p&gt;| 12 client hampers at ₹25,000 each, before GST | 3,00,000 | Each above ₹20,000. 10% TDS is ₹2,500 per client, ₹30,000 in all, on the pre-GST value | GST ₹4,500 per hamper, ₹54,000 in all, blocked ITC |&lt;/p&gt;

&lt;p&gt;| One cash bonus to an employee in the 20% slab | 12,000 | Salary. At a 20% slab plus cess (20.8%) the extra tax is ₹2,496 | None |&lt;/p&gt;

&lt;p&gt;Now the cash view. Total spend on gifts and bonus is ₹1,80,000 + ₹3,54,000 (clients with GST) + ₹12,000 = ₹5,46,000. Blocked ITC is ₹27,458 + ₹54,000 = ₹81,458, which is 15.3% of the gift spend and a cost you carry whatever you do. The client TDS of ₹30,000 is a separate cash outflow unless the clients give you advance tax challans. If you absorb the tax yourself, gross it up (Circular 12/2022, Q9): the tax is itself a benefit, so TDS is ₹3,00,000 × 10/90 = ₹33,333, not ₹30,000 (₹2,778 per client), and the outflow is about ₹5,79,333.&lt;/p&gt;

&lt;p&gt;On the recipient side, none of the 12 clients owes tax under the ₹50,000 rule on a hamper of this size, but each treats the benefit under its own head of income and claims the ₹2,500 as TDS credit. One ₹11,000 voucher in July turned Meera's tax-free hamper into ₹4,836 of tax. Check the annual tally before the purchase order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Employer checklist for Diwali 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Now to 30 October | List every gift each employee has received since 1 April 2026; cap the Diwali gift so the total stays below ₹15,000 |&lt;/p&gt;

&lt;p&gt;| Now to 30 October | Total each client's benefits since 1 April; flag anyone above ₹20,000 for 194R |&lt;/p&gt;

&lt;p&gt;| By 3 November | Ask the accounts team to mark gift invoices as blocked ITC in the purchase register |&lt;/p&gt;

&lt;p&gt;| Before 6 November | Obtain client advance tax challans or arrange to pay the 10% yourself, before releasing gifts in kind |&lt;/p&gt;

&lt;p&gt;| 6 November (Dhanteras) | Pay gold and bullion purchases by bank or UPI; no cash at ₹2 lakh or more |&lt;/p&gt;

&lt;p&gt;| 8 November (Diwali) | Gifts and bonus go out |&lt;/p&gt;

&lt;p&gt;| By 20 November | October GSTR-3B: confirm no gift credit was claimed |&lt;/p&gt;

&lt;p&gt;| By 7 December | Deposit TDS deducted in November (194R and salary TDS); Rule 218 of the Income-tax Rules 2026 (Rule 30 of the 1962 Rules): by the 7th of the following month, and 30 April for March deductions[19]. 194R deducted on gifts released in October is due by 7 November; November deductions by 7 December. No separate form |&lt;/p&gt;

&lt;p&gt;| By 30 April 2027 | Form 123, only if salary exceeds ₹1,50,000 a year and the perquisite value is not nil, issued alongside Form 130, the salary TDS certificate[3] |&lt;/p&gt;

&lt;p&gt;Plan the festival budget itself with the &lt;a href="https://dev.to/tools/diwali-2026-budget-planner"&gt;Diwali budget planner&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the tax-free Diwali gift limit for employees in 2026?
&lt;/h3&gt;

&lt;p&gt;Nil perquisite value applies only when gifts, vouchers and tokens from the employer total below ₹15,000 in tax year 2026-27, under Rule 15 of the Income-tax Rules 2026. The earlier limit was ₹5,000. Cash is always taxable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the whole gift taxed if I go over ₹15,000?
&lt;/h3&gt;

&lt;p&gt;Yes. Rule 15 values the gift at the sum equal to the amount of the gift, and nil only if the year's total is below ₹15,000.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a company claim GST credit on Diwali gifts?
&lt;/h3&gt;

&lt;p&gt;No, for gifts up to ₹50,000 per employee a year and for client gifts. Section 17(5)(h) blocks credit on goods given as gifts. Credit is available only when a gift exceeds ₹50,000 and becomes a taxable supply under Schedule I.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does TDS apply when I give a gift to a client?
&lt;/h3&gt;

&lt;p&gt;Yes, if you carry on a business or profession and the total benefit to that resident in the financial year goes above ₹20,000. The rate is 10% under section 194R, now section 393(1) of the 2025 Act, on the value without GST. Individuals and HUFs under ₹1 crore of business turnover or ₹50 lakh of professional receipts are exempt as givers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I pay tax on a Diwali gift from a friend or relative?
&lt;/h3&gt;

&lt;p&gt;Gifts from relatives are exempt. A friend who is not a relative can give you up to ₹50,000 in the tax year, in aggregate, without tax. Above that, the whole amount is taxable. Diwali is not a listed occasion, unlike marriage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the Diwali bonus covered by the gift limit?
&lt;/h3&gt;

&lt;p&gt;No. A bonus is salary and is taxed at your slab with TDS. Statutory bonus applies to employees earning up to ₹21,000 a month, with a floor of 8.33% and a ceiling of 20% of capped wages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://kpmg.com/xx/en/our-insights/gms-flash-alert/2026/flash-alert-2026-081.html" rel="noopener noreferrer"&gt;KPMG, Flash Alert 2026-081: Income-tax Rules 2026 notified 20 March 2026, gift limit raised from ₹5,000 to ₹15,000 (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/w/section-194r-4" rel="noopener noreferrer"&gt;Income Tax Department, Section 194R, 1961 Act (accessed 16 October 2026, read from the search extract because the page blocked direct fetch)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/documents/d/guest/form-123-faqs" rel="noopener noreferrer"&gt;Income Tax Department, Form 123 FAQs: s.392(5)(a), Rule 204(2), old Form 12BA, s.192, Rule 26A (accessed 16 October 2026, read from the search extract because the page blocked direct fetch)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.tdsman.com/2026/08/tds-on-benefit-or-perquisite-section-3931-194r/" rel="noopener noreferrer"&gt;TDSMAN, TDS on Benefit or Perquisite, s.393(1) table serial 8(iv) (secondary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cleartax.in/s/income-tax-act-2025-section-numbers-old-vs-new" rel="noopener noreferrer"&gt;ClearTax, Income-tax Act 2025 section numbers, old vs new (secondary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://eztax.in/income-tax-act-2025/section-92" rel="noopener noreferrer"&gt;EZTax, Income-tax Act 2025 section 92 text, clause (m) and sub-section (3) exceptions (secondary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/w/rule-15-23" rel="noopener noreferrer"&gt;Income Tax Department, Income-tax Rules 2026, Rule 15(5)(a), Table IV, item 4 (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/w/rule-218-1" rel="noopener noreferrer"&gt;Income Tax Department, Income-tax Rules 2026, Rule 218, deposit of tax deducted at source (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/w/section-56-64" rel="noopener noreferrer"&gt;Income Tax Department, section 56 (1961 Act) gift provisions and exceptions (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.vantagecircle.com/en/blog/recognition-rewards-tax-rules-india/" rel="noopener noreferrer"&gt;Vantage Circle, Recognition and rewards tax rules, Rule 15(5)(a) Table IV (secondary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://taxinformation.cbic.gov.in/content/html/tax_repository/gst/acts/2017_CGST_act/active/chapter21/schedulei_v1.00.html" rel="noopener noreferrer"&gt;CBIC, CGST Act 2017, Schedule I, item 2 and proviso (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cbic-gst.gov.in/pdf/press-release/pres-rls-gst-gift-dt10july.pdf" rel="noopener noreferrer"&gt;CBIC, Press Release on GST treatment of gifts and perquisites, July 2017 (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gstcouncil.gov.in/sites/default/files/2024-06/circular-cgst-92.pdf" rel="noopener noreferrer"&gt;CBIC, Circular 92/11/2019-GST of 7 March 2019, sales promotion schemes, paragraph A(ii) on section 17(5)(h) (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gstcouncil.gov.in/sites/default/files/2025-01/circular-no-243-2024.pdf" rel="noopener noreferrer"&gt;CBIC, Circular 243/37/2024-GST of 31 December 2024, GST treatment of vouchers (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.taxheal.com/cbdt-circular-no-12-of-2022.html" rel="noopener noreferrer"&gt;CBDT, Circular 12/2022 of 16 June 2022 on section 194R, reproduced by Taxheal (secondary copy; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://taxguru.in/income-tax/cbdt-issues-additional-guidelines-tds-section-194r.html" rel="noopener noreferrer"&gt;CBDT, Circular 18/2022 of 13 September 2022 on section 194R, reproduced by TaxGuru (secondary copy; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gstcouncil.gov.in/sites/default/files/2024-02/sectoral-fq-gems-jewellery.pdf" rel="noopener noreferrer"&gt;CBIC, Sectoral FAQ on gems and jewellery, questions 7 and 8 (2017 FAQ; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://startuptalky.com/section-269st-income-tax-act-india-explained/" rel="noopener noreferrer"&gt;StartupTalky, Section 269ST cash receipt limit explained (secondary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.khaitanco.com/sites/default/files/2026-09/Ergo_Bonus%20Payout_04%20September%202026.pdf" rel="noopener noreferrer"&gt;Khaitan and Co, Ergo alert on notifications S.O. 4710(E) and S.O. 4711(E) of 25 August 2026 under the Code on Wages (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.mondaq.com/ministry-of-labour-and-employment-operationalises-the-provisions-on-payment-of-statutory-bonus/1842516" rel="noopener noreferrer"&gt;Mondaq, Ministry of Labour operationalises statutory bonus provisions (secondary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Every product mentioned is available at wowhow.cloud — pay once, ship forever.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/diwali-gifts-tax-gst-tds-rules-india-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>diwaligifts</category>
      <category>employeegift</category>
      <category>section194r</category>
      <category>gston</category>
    </item>
    <item>
      <title>GSTR-9 and 9C FY 2025-26 Checklist (Due 31 Dec 2026)</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Fri, 16 Oct 2026 07:16:48 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/gstr-9-and-9c-fy-2025-26-checklist-due-31-dec-2026-jgj</link>
      <guid>https://dev.to/akaranjkar08/gstr-9-and-9c-fy-2025-26-checklist-due-31-dec-2026-jgj</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; If your aggregate turnover for FY 2025-26 (1 April 2025 to 31 March 2026) is above ₹2 crore, you file GSTR-9 by 31 December 2026. Above ₹5 crore, you also file a self-certified GSTR-9C, and the return counts as filed only when both are in. Under ₹2 crore you are exempt. Reconcile books against GSTR-1, GSTR-3B and GSTR-2B now, pay any shortfall through DRC-03 before you file, and do not file GSTR-9 before you have claimed all eligible credit, because the section 16(4) cut-off is the earlier of 30 November 2026 or your GSTR-9 filing date. There is no revision after you file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GSTR-9 and GSTR-9C for FY 2025-26 are due on Thursday, 31 December 2026, which is 76 days from today, 16 October.&lt;/strong&gt; Notification 15/2025-Central Tax exempts registered persons with aggregate turnover up to ₹2 crore for FY 2024-25 onwards[1], and Rule 80(3) requires the GSTR-9C reconciliation only above ₹5 crore[2]. The late fee for missing the date runs per day, for the days until the complete return is filed[3]. This post covers who files what, which numbers come pre-filled and which you can edit, a table-by-table checklist, the 2023 late fee slabs, interest on additional tax, a worked ₹1.3 lakh mismatch, and a dated calendar to 31 December.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who must file GSTR-9, GSTR-9C or neither
&lt;/h2&gt;

&lt;p&gt;Section 44 of the CGST Act requires every registered person except specified classes to file an annual return. Notification 15/2025-Central Tax, dated 17 September 2025, uses the first proviso to section 44(1) to exempt a registered person whose aggregate turnover in a financial year is up to ₹2 crore, "in respect of filing of annual return for the financial year 2024-25 onwards"[1]. That wording means FY 2025-26 is covered without a fresh notification. The exemption is per year and tied to that year's turnover, so check FY 2025-26 turnover, not last year's.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aggregate turnover FY 2025-26&lt;/th&gt;
&lt;th&gt;GSTR-9&lt;/th&gt;
&lt;th&gt;GSTR-9C&lt;/th&gt;
&lt;th&gt;Basis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Up to ₹2 crore | Exempt | Not required | Notification 15/2025-CT[1] |&lt;/p&gt;

&lt;p&gt;| Above ₹2 crore, up to ₹5 crore | Required | Not required | Section 44(1); Rule 80(3)[2] |&lt;/p&gt;

&lt;p&gt;| Above ₹5 crore | Required | Required, self-certified | Rule 80(3), as substituted by Notification 30/2021-CT[2] |&lt;/p&gt;

&lt;p&gt;| Composition taxpayer | GSTR-4 annual return, not GSTR-9 | Not required | GSTN treats GSTR-4 as replacing GSTR-9A since FY 2019-20, though the Rule 80(1) proviso as substituted by Notification 30/2021 still names GSTR-9A. Verify the form on the portal |&lt;/p&gt;

&lt;p&gt;Three points that trip people up.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The exemption removes the obligation; it does not remove GSTR-1 or GSTR-3B. A ₹1.8 crore business still files every monthly or quarterly return.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Aggregate turnover is PAN-wide across all GSTINs, and it includes exempt and export supplies. A business with two GSTINs of ₹1.2 crore each crosses ₹2 crore and both GSTINs file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Since FY 2020-21 the GSTR-9C is a self-certified statement, not a CA-audited one. A chartered accountant is no longer mandatory, though many firms still sign off before the owner does.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The due date and what is open on the portal
&lt;/h2&gt;

&lt;p&gt;The FY 2025-26 due date is 31 December 2026, the statutory pattern for every year since the form began. GSTN Advisory No. 677 (reported dated 13 October 2026) says filing has been enabled with effect from 8 October 2026; another report says 10 October[4]. The advisory page itself sits behind a CAPTCHA, so treat the exact day as reported, not confirmed. The prerequisite is that every FY 2025-26 GSTR-1 and GSTR-3B is filed. Check Services &amp;gt; Returns &amp;gt; Annual Return on the portal before you plan around it. Plan for 31 December.&lt;/p&gt;

&lt;p&gt;Where GSTR-9C is required, CBIC Circular 246/03/2025-GST makes the annual return "complete" only when both forms are filed[3]. Filing GSTR-9 on 30 December and GSTR-9C on 15 January means late fee runs for 15 days, from the due date to the date of the later form. The circular spells out both cases: the date of GSTR-9 if GSTR-9C is filed with it, or the date of GSTR-9C if filed later[3].&lt;/p&gt;

&lt;h2&gt;
  
  
  What is auto-populated and what you can edit
&lt;/h2&gt;

&lt;p&gt;The portal pre-fills much of GSTR-9 from your filed returns. Per the commercial guides I checked, which cite GSTN's FAQs, Tables 4, 5, 6, 8 and 9 are partly drawn from GSTR-1, GSTR-1A, IFF, GSTR-2B and GSTR-3B, and the figures can be edited[5]. Table 8A comes from GSTR-2B and Table 8B from Table 6B[5]. The practical rule: the pre-fill is a starting point, not an answer. If your books say ₹8.42 crore and the portal says ₹8.38 crore, you do not accept the portal. You find out why.&lt;/p&gt;

&lt;p&gt;Because GSTR-2B reflects your Invoice Management System actions, an invoice you rejected in IMS will not feed Table 8A. That is one reason the sibling post on the credit cut-off matters here: read the &lt;a href="https://dev.to/blogs/gst-itc-deadline-30-november-2026-fy-2025-26-claim-guide"&gt;GST ITC deadline guide for 30 November 2026&lt;/a&gt; before you touch Tables 6 and 8.&lt;/p&gt;

&lt;h3&gt;
  
  
  Form changes that came in with FY 2024-25
&lt;/h3&gt;

&lt;p&gt;Secondary sources disagree on the year each change started, so treat this list as a prompt to open the live form.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Table 6A1&lt;/strong&gt; captures ITC of the preceding year claimed in the current year's GSTR-3B, excluding Rule 37/37A reclaims, which belong in Table 6H[5].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Table 7A1&lt;/strong&gt; records ITC reversed under Rule 37A where the supplier had not filed GSTR-3B[5].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Table 8H1&lt;/strong&gt; takes IGST on current-year imports that you availed in the next year, instead of Table 6E[5].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Table 8C&lt;/strong&gt; was narrowed to ITC that appeared in GSTR-2B but you did not claim, plus, per GSTN FAQ summaries, invoices the seller uploaded between April and October of the next year[6].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rate-wise lines&lt;/strong&gt; need attention because FY 2025-26 straddles the 22 September 2025 rate restructuring, so Tables 9 to 11 and 17 may need two rate sets for the same HSN[4].&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Table-by-table checklist
&lt;/h2&gt;

&lt;p&gt;This is the working order I would use. The source column says where each number should come from. The mandatory-versus-optional split below is for FY 2024-25 as listed by StudyCafe[7]. I found no FY 2025-26 notification changing it, but the portal form for your year is the final word.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GSTR-9 table&lt;/th&gt;
&lt;th&gt;What goes in&lt;/th&gt;
&lt;th&gt;Source to reconcile with&lt;/th&gt;
&lt;th&gt;Status (FY 2024-25 pattern)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| 4 (A to G, I to L) | Outward taxable supplies, exports, SEZ, RCM, advances, credit and debit notes, amendments | GSTR-1, GSTR-1A, GSTR-3B; books | Mandatory |&lt;/p&gt;

&lt;p&gt;| 5 (A to F) | Exempt, nil-rated, non-GST outward supplies | GSTR-1, GSTR-3B Table 3.1 | Mandatory |&lt;/p&gt;

&lt;p&gt;| 5H to 5K | Credit and debit note adjustments in the outward block | Can be folded into 5A to 5F | Optional |&lt;/p&gt;

&lt;p&gt;| 6 (A to M) | ITC availed: inputs, services, capital goods, imports, ISD, 6A1 and 6H reclaims | GSTR-3B Table 4, GSTR-2B, purchase register | Mandatory |&lt;/p&gt;

&lt;p&gt;| 7 (A to G) | ITC reversed and ineligible, incl. Rule 37, 37A, 42, 43, section 17(5) | GSTR-3B Table 4B; ITC reversal ledger | Mandatory |&lt;/p&gt;

&lt;p&gt;| 8 (A to K) | ITC per GSTR-2B vs availed vs ineligible; carryover 8C | GSTR-2B for all 12 months plus April to October of the next year | Mandatory |&lt;/p&gt;

&lt;p&gt;| 9 | Tax payable and tax paid, cash vs ITC, by head | GSTR-3B Table 6.1; electronic ledgers | Mandatory |&lt;/p&gt;

&lt;p&gt;| 10 to 11 | FY 2025-26 supplies and credit/debit notes reported in April to November 2026 returns | GSTR-1 and 3B filed through November 2026 | Mandatory |&lt;/p&gt;

&lt;p&gt;| 12 to 13 | Reversal of FY 2025-26 ITC, and FY 2025-26 ITC availed, in GSTR-3B for April to November 2026 (or the GSTR-9 filing date if earlier) | GSTR-3B April to November 2026 | Check form (sources conflict on whether mandatory) |&lt;/p&gt;

&lt;p&gt;| 14 | Differential tax paid on 10 and 11 | DRC-03 or GSTR-3B | Mandatory where applicable |&lt;/p&gt;

&lt;p&gt;| 15 to 16 | Demands and refunds; supplies received from composition dealers, deemed supply, goods on approval | Refund and order register | Optional |&lt;/p&gt;

&lt;p&gt;| 17 | HSN summary of outward supplies | GSTR-1 Table 12 | Mandatory |&lt;/p&gt;

&lt;p&gt;| 18 | HSN summary of inward supplies | Purchase register | Optional |&lt;/p&gt;

&lt;p&gt;| 19 | Late fee payable and paid | Electronic cash ledger | Computed by portal |&lt;/p&gt;

&lt;p&gt;Table 10 and 11 deserve extra care. A sales invoice dated 28 March 2026 that you add to GSTR-1 in May 2026 belongs in Table 10 of the FY 2025-26 return, not in Table 4. Leave Part V (Tables 10 to 14) blank when it should not be, and the annual return shows a false position against your filed monthly returns[5].&lt;/p&gt;

&lt;h3&gt;
  
  
  HSN digits in Table 17
&lt;/h3&gt;

&lt;p&gt;Notification 78/2020-Central Tax (effective 1 April 2021) sets the HSN digits on tax invoices by preceding-year turnover: 4 digits up to ₹5 crore, 6 digits above[8]. Table 17 is reported on the same 4/6-digit split; the portal validation enforces it. The B2B-only relaxation for smaller filers comes from secondary guides[7], so check the live form instructions. The &lt;a href="https://dev.to/tools/hsn-code-finder"&gt;HSN code finder&lt;/a&gt; gives the 6 and 8 digit code and the current rate, and the &lt;a href="https://dev.to/tools/gstin-validator"&gt;GSTIN validator&lt;/a&gt; catches typos in the vendor list you will need for Table 8.&lt;/p&gt;

&lt;h2&gt;
  
  
  GSTR-9C: what the reconciliation statement asks
&lt;/h2&gt;

&lt;p&gt;Above ₹5 crore, GSTR-9C reconciles audited or book turnover against the GSTR-9 figure in Part II, and ITC per books against ITC per GSTR-9 in Part III. Per StudyCafe's list for FY 2024-25, Tables 5A, 7A to 7F, 9A to 9Q and 12A to 12D are mandatory; 5B to 5O (foldable into 5O) and 14 are optional[7].&lt;/p&gt;

&lt;h2&gt;
  
  
  Late fee under section 47(2) and Notification 07/2023
&lt;/h2&gt;

&lt;p&gt;The default late fee under section 47(2) is ₹100 a day for the period of default under the CGST Act, with an equal SGST amount, capped at a quarter of one percent of turnover in the State or Union territory under each Act. I could not fetch the Act's text from a primary page, so that statement rests on a CBIC circular's discussion and two secondary summaries[3][9]. The relief for smaller taxpayers is primary-sourced. Notification 07/2023-Central Tax, dated 31 March 2023, waives the late fee above the amounts below for returns under section 44 "for the financial year 2022-23 onwards"[10].&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aggregate turnover&lt;/th&gt;
&lt;th&gt;Per day (CGST)&lt;/th&gt;
&lt;th&gt;Cap (CGST)&lt;/th&gt;
&lt;th&gt;Total with SGST&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Up to ₹5 crore | ₹25 | 0.02% of turnover in the State/UT | ₹50 a day; cap 0.04% |&lt;/p&gt;

&lt;p&gt;| Above ₹5 crore, up to ₹20 crore | ₹50 | 0.02% of turnover in the State/UT | ₹100 a day; cap 0.04% |&lt;/p&gt;

&lt;p&gt;| Above ₹20 crore | ₹100 (no waiver) | 0.25% of turnover in the State/UT | ₹200 a day; cap 0.50% |&lt;/p&gt;

&lt;p&gt;The notification has only two rows, and the top row says "Twenty-five rupees per day, subject to a maximum of an amount calculated at 0.02 per cent. of turnover"[10]. The third row is what is left when no waiver applies, so it is the section 47(2) default, and the 0.50% combined cap follows from the 0.25% CGST cap doubled for SGST. The late fee is paid from the electronic cash ledger and cannot be set off against ITC[5]. Use the &lt;a href="https://dev.to/tools/gst-late-fee-interest-calculator"&gt;GST late fee and interest calculator&lt;/a&gt; for the exact day count.&lt;/p&gt;

&lt;p&gt;An example: a trader with ₹12 crore turnover in one State files the complete return 25 days late. The rate is ₹50 + ₹50 = ₹100 a day, so 25 × ₹100 = ₹2,500. The cap is 0.02% × ₹12,00,00,000 = ₹24,000 per Act, ₹48,000 together. The cap is far away, so the fee is ₹2,500. The notification has no waiver for default beyond ₹20 crore, so a ₹30 crore business filing 25 days late pays 25 × ₹200 = ₹5,000.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interest and DRC-03 on additional liability
&lt;/h2&gt;

&lt;p&gt;If reconciliation shows you under-reported outward tax, pay the shortfall before filing GSTR-9. The route is Form GST DRC-03 from the cash ledger, with interest, and then you report the payment in Table 9; Table 14 is for differential tax on next-year adjustments, though secondary guides vary on this[5]. Interest on short-paid tax runs under section 50(1) at 18% a year from the day after the original due date to the payment date. The rates come from Notification 13/2017-Central Tax (28 June 2017): 18% under section 50(1) and 24% under section 50(3), confirmed via ICAI and Taxmann reproductions because the CBIC PDF was unavailable[12]. ITC wrongly availed and utilised draws the higher 24%, so reverse those first.&lt;/p&gt;

&lt;p&gt;Missed ITC is a different story. One secondary guide says missed ITC generally cannot be claimed after you file GSTR-9, and that demand notices for FY 2024-25 onward are issued under section 74A[5]. Neither point is primary-sourced here.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reconciliation workflow: books, GSTR-1, GSTR-3B, GSTR-2B
&lt;/h2&gt;

&lt;p&gt;Run the four-way match in this order, because each step feeds the next.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Books vs GSTR-1.&lt;/strong&gt; Compare monthly taxable value by rate. Differences are usually March invoices left out, or credit notes booked in a different month.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GSTR-1 vs GSTR-3B.&lt;/strong&gt; Compare Table 3.1(a) to GSTR-1 totals. The gap is the cleanest evidence of under-reported tax.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Purchase register vs GSTR-2B.&lt;/strong&gt; This sets Tables 6 and 8. The &lt;a href="https://dev.to/product/gst-itc-rescue-workbook-fy2025-26"&gt;GST ITC Rescue Workbook for FY 2025-26&lt;/a&gt; has a 2B-versus-books matcher with section 16(4) flags if you do not already have one; a spreadsheet pivot works as well.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ITC availed vs ITC due.&lt;/strong&gt; Strip blocked credits under section 17(5), reverse Rule 37 and 37A items, then compare to GSTR-3B Table 4.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tax paid vs tax payable.&lt;/strong&gt; Compare Table 9 to the ledger and note any liability paid late.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Worked example: a ₹1.3 lakh mismatch
&lt;/h3&gt;

&lt;p&gt;An illustrative Ahmedabad trader has ₹8.4 crore of FY 2025-26 turnover, so it files GSTR-9 and GSTR-9C. The reconciliation on 16 October gives these taxable-value totals:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Taxable outward value (₹)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Books (sales ledger) | 8,42,60,000 |&lt;/p&gt;

&lt;p&gt;| GSTR-1 (all months) | 8,38,10,000 |&lt;/p&gt;

&lt;p&gt;| GSTR-3B Table 3.1(a) | 8,35,40,000 |&lt;/p&gt;

&lt;p&gt;The math:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Books minus GSTR-1: 8,42,60,000 − 8,38,10,000 = ₹4,50,000. These are March 2026 invoices never uploaded to GSTR-1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GSTR-1 minus GSTR-3B: 8,38,10,000 − 8,35,40,000 = ₹2,70,000. These were reported in GSTR-1 but left out of the 3B.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Total unreported value: ₹4,50,000 + ₹2,70,000 = ₹7,20,000.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tax at 18%: ₹7,20,000 × 0.18 = &lt;strong&gt;₹1,29,600&lt;/strong&gt;, i.e. ₹64,800 CGST and ₹64,800 SGST.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Interest at 18% a year from 21 April 2026, the day after the 20 April due date, to 20 December 2026, 244 days: 1,29,600 × 0.18 × 244 ÷ 365 = ₹15,594.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The example treats every difference as belonging to the March 2026 period, so a single interest start date applies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cash needed through DRC-03: ₹1,29,600 + ₹15,594 = ₹1,45,194.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the credit side, GSTR-2B shows ITC of ₹21,40,000 against ₹22,10,000 in the purchase register, a gap of ₹70,000. Of that, ₹52,000 is one vendor who never filed GSTR-1, so the invoices are missing from GSTR-2B, and ₹18,000 is catering that section 17(5) blocks. Neither can be fixed in Table 8 by editing a number; the vendor has to file, or the claim stays out of the return. The ₹52,000 is the item with a clock on it, since credit not claimed by 30 November is gone. Pay the ₹1,45,194 first, report it, and only then file. Found now, the exposure is ₹1,45,194. Found in a notice instead, the same tax would carry section 74A interest and penalty on top.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the 30 November ITC cut-off interacts with GSTR-9
&lt;/h2&gt;

&lt;p&gt;Section 16(4) bars credit after the earlier of 30 November following the financial year or the date you file the annual return. Filing GSTR-9 on 5 November 2026 makes 5 November your cut-off. The full mechanics, Rule 37 and Rule 37A reversals and the October 3B due 20 November are in the &lt;a href="https://dev.to/blogs/gst-itc-deadline-30-november-2026-fy-2025-26-claim-guide"&gt;sibling ITC deadline guide&lt;/a&gt;. Sequence matters: file GSTR-9 only after the October 2026 GSTR-3B, which is the last monthly return that can carry FY 2025-26 credit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes CAs see every December
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filing early to be done.&lt;/strong&gt; A GSTR-9 filed on 10 November resets the ITC cut-off to 10 November.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Accepting the pre-fill.&lt;/strong&gt; Tables 4 and 6 fill from filed returns, so errors in those returns carry straight in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Forgetting GSTR-9C is a second filing.&lt;/strong&gt; Late fee runs until both are in[3].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filing with pending returns.&lt;/strong&gt; One report says the portal is blocking annual return filing by asking for pending GSTR-1 and 3B that are already filed, with no GSTN fix confirmed[4].&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Dated calendar: 16 October to 31 December 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Fri 16 to Sun 18 Oct | Pull books, GSTR-1, GSTR-3B and the twelve GSTR-2B statements; run the four-way match |&lt;/p&gt;

&lt;p&gt;| Tue 20 Oct | September GSTR-3B for monthly filers; correct any current-year miss in this return |&lt;/p&gt;

&lt;p&gt;| Thu 22 or Sat 24 Oct | QRMP quarterly GSTR-3B (state-based date) |&lt;/p&gt;

&lt;p&gt;| Sun 1 to Sat 7 Nov | Clear IMS on FY 2025-26 invoices; chase vendors |&lt;/p&gt;

&lt;p&gt;| Wed 11 Nov | Vendors' October GSTR-1 due; last clean date for late invoices to appear |&lt;/p&gt;

&lt;p&gt;| Sat 14 Nov | October GSTR-2B generates; re-run the match |&lt;/p&gt;

&lt;p&gt;| Fri 20 Nov | October GSTR-3B; claim, reverse and pay |&lt;/p&gt;

&lt;p&gt;| Mon 30 Nov | Section 16(4) cut-off and last day to claim FY 2025-26 credit if GSTR-9 is not yet filed |&lt;/p&gt;

&lt;p&gt;| Tue 1 to Fri 11 Dec | Pay any shortfall by DRC-03; freeze the numbers; prepare GSTR-9 drafts |&lt;/p&gt;

&lt;p&gt;| Thu 31 Dec | Due date for GSTR-9 and GSTR-9C. File both well before the day |&lt;/p&gt;

&lt;p&gt;Load these into the &lt;a href="https://dev.to/tools/gst-compliance-calendar-2026"&gt;GST compliance calendar for 2026&lt;/a&gt; so reminders reach the whole team. Verify every date on the GST portal, since extensions are common.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is GSTR-9 mandatory for FY 2025-26?
&lt;/h3&gt;

&lt;p&gt;Yes, if aggregate turnover exceeds ₹2 crore. Notification 15/2025-Central Tax exempts those up to ₹2 crore for FY 2024-25 onwards.&lt;/p&gt;

&lt;h3&gt;
  
  
  When is GSTR-9C required?
&lt;/h3&gt;

&lt;p&gt;When aggregate turnover for the year exceeds ₹5 crore, under Rule 80(3). It is self-certified, and the annual return is complete only when both GSTR-9 and GSTR-9C are filed.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the late fee for GSTR-9?
&lt;/h3&gt;

&lt;p&gt;Under Notification 07/2023-CT it is ₹50 a day in total (₹25 CGST plus ₹25 SGST) up to ₹5 crore, ₹100 a day for ₹5 to ₹20 crore, each capped at 0.04% of turnover; above ₹20 crore the section 47(2) default of ₹200 a day applies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I revise GSTR-9 after filing?
&lt;/h3&gt;

&lt;p&gt;No. There is no revision facility. Short-paid tax is paid afterwards through DRC-03 with interest, so reconcile before you file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does filing GSTR-9 early affect my ITC?
&lt;/h3&gt;

&lt;p&gt;Yes. Under section 16(4) the credit cut-off is the earlier of 30 November 2026 or your GSTR-9 filing date, so an early filing shortens your own window.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I report FY 2025-26 invoices filed after March 2026?
&lt;/h3&gt;

&lt;p&gt;Yes. Supplies and notes reported in April to November 2026 returns that belong to FY 2025-26 go in Tables 10 and 11, and any differential tax in Table 14.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://taxo.online/wp-content/uploads/2025/09/centaltax-15-2025.pdf" rel="noopener noreferrer"&gt;Notification 15/2025-Central Tax, 17 September 2025, gazette text as hosted by Taxo (mirrored PDF, read in full)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gstcouncil.gov.in/sites/default/files/2024-05/notfctn-30-central-tax-english-2021.pdf" rel="noopener noreferrer"&gt;Notification 30/2021-Central Tax, substituting Rule 80 (found by search; text not fully read)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cbic-gst.gov.in/pdf/cir-cgst-246-03-2025.pdf" rel="noopener noreferrer"&gt;CBIC, Circular 246/03/2025-GST on late fee for delay in GSTR-9C&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://studycafe.in/gst-portal-opens-gstr-9-and-gstr-9c-filing-for-fy-2025-26-check-due-date-and-key-points-427389.html" rel="noopener noreferrer"&gt;StudyCafe, GST Portal Opens GSTR-9 and GSTR-9C Filing for FY 2025-26, 12 October 2026, and GSTN Advisory No. 677 as reported (secondary)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://taxgarden.in/blog/gstr-9-annual-return-filing-guide-fy-2025-26-india" rel="noopener noreferrer"&gt;Tax Garden, GSTR-9 annual return filing guide for FY 2025-26 (secondary)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://studycafe.in/gstr-9-9c-fy-2024-25-key-updates-new-tables-and-filing-insights-ahead-of-dec-31-deadline-397203.html" rel="noopener noreferrer"&gt;StudyCafe, GSTR-9/9C FY 2024-25 key updates, 25 October 2025 (secondary)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://studycafe.in/gstr-9-9c-mandatory-vs-optional-tables-for-fy-2024-25-399440.html" rel="noopener noreferrer"&gt;StudyCafe, GSTR-9 and 9C mandatory vs optional tables for FY 2024-25 (secondary)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Notification 13/2017-Central Tax, 28 June 2017, interest rates under section 50 (number and date cited; text confirmed via ICAI and Taxmann reproductions)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.gstcouncil.gov.in/sites/default/files/2024-05/notfctn-78-central-tax-english-2020.pdf" rel="noopener noreferrer"&gt;Notification 78/2020-Central Tax, HSN digits by turnover, effective 1 April 2021 (found by search; text not fully read)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://taxguru.in/goods-and-service-tax/consequences-not-filing-gst-annual-return.html" rel="noopener noreferrer"&gt;TaxGuru, Consequences of not filing GST annual return (secondary)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gstcouncil.gov.in/sites/default/files/2024-05/07_eng.pdf" rel="noopener noreferrer"&gt;Notification 07/2023-Central Tax, 31 March 2023 (read in full)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This article is for informational purposes only and does not constitute financial, tax, or legal advice. Consult a qualified professional for advice specific to your situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every product mentioned is available at wowhow.cloud — pay once, ship forever.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/gstr-9-gstr-9c-fy-2025-26-filing-checklist-31-december-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gstr9fy</category>
      <category>gstr9cfy</category>
      <category>gstr9due</category>
      <category>gstr9late</category>
    </item>
    <item>
      <title>Postgres timestamp vs timestamptz 2026: Rule and Migration</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Fri, 16 Oct 2026 07:16:16 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/postgres-timestamp-vs-timestamptz-2026-rule-and-migration-41aa</link>
      <guid>https://dev.to/akaranjkar08/postgres-timestamp-vs-timestamptz-2026-rule-and-migration-41aa</guid>
      <description>&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;timestamptz&lt;/code&gt; for every column that records a moment in time, store it as UTC, and convert to a local zone only when you display it.&lt;/strong&gt; Both types take 8 bytes and have 1 microsecond resolution[1], so the choice costs nothing in space. What differs is meaning: &lt;code&gt;timestamptz&lt;/code&gt; stores an instant, while &lt;code&gt;timestamp&lt;/code&gt; stores a wall-clock reading with no zone attached, and Postgres will silently drop any offset you give it. That one fact produces four classic bugs: a server &lt;code&gt;TimeZone&lt;/code&gt; change that shifts readings, DST gaps and overlaps, &lt;code&gt;now()&lt;/code&gt; compared against the wrong type, and &lt;code&gt;AT TIME ZONE&lt;/code&gt; applied twice. Below: what each type stores, a behaviour table, the bugs with runnable SQL, ORM defaults as of October 2026, the one exception, and a migration recipe.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The SQL standard name for plain &lt;code&gt;timestamp&lt;/code&gt; is "timestamp without time zone". That name is the footgun: it stores no zone and ignores one in the input[1].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;timestamptz&lt;/code&gt; does not store a zone either. It converts to UTC on input and back to the session &lt;code&gt;TimeZone&lt;/code&gt; on output[1].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prisma, Drizzle and Rails default to the zone-less type. Django's PostgreSQL backend uses the zone-aware one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The one exception: a future local-time appointment ("9:00 in Kolkata on 3 March") should keep the local time plus an IANA zone name.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Migrating: on PostgreSQL 12 and later, an in-place type change can skip the table rewrite when the session zone is UTC[5]. Otherwise use the add-column, backfill, swap route.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What each type actually stores
&lt;/h2&gt;

&lt;p&gt;The name &lt;code&gt;timestamp with time zone&lt;/code&gt; misleads people into thinking the zone is saved. It is not. The docs say an input with an explicit zone is converted to UTC, an input without one is assumed to be in the session &lt;code&gt;TimeZone&lt;/code&gt; and then converted, and in either case the value is stored as UTC and the original zone is not retained[1]. On output the value is converted from UTC to the current &lt;code&gt;TimeZone&lt;/code&gt; setting[1]. So &lt;code&gt;timestamptz&lt;/code&gt; is a point on the UTC timeline, rendered through whatever zone the session has.&lt;/p&gt;

&lt;p&gt;Plain &lt;code&gt;timestamp&lt;/code&gt; is a date and a clock reading, nothing else. Postgres never inspects a string before choosing its type, so &lt;code&gt;TIMESTAMP '2004-10-19 10:23:54+02'&lt;/code&gt; is zone-less and the docs say Postgres "will silently ignore any time zone indication"[1]. Write &lt;code&gt;TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02'&lt;/code&gt; if you mean it. Bare &lt;code&gt;timestamp&lt;/code&gt; means the zone-less type per the SQL standard[1], which is the wrong default for most applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behaviour comparison: timestamp vs timestamptz
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;th&gt;timestamp&lt;/th&gt;
&lt;th&gt;timestamptz&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Storage and resolution | 8 bytes, 1 microsecond | 8 bytes, 1 microsecond |&lt;/p&gt;

&lt;p&gt;| What is stored | Date and clock fields as written | A UTC instant |&lt;/p&gt;

&lt;p&gt;| Offset in the input string (&lt;code&gt;+02&lt;/code&gt;) | Silently ignored | Used to convert to UTC |&lt;/p&gt;

&lt;p&gt;| Output | Same fields every time, whatever the session zone | Converted to the session &lt;code&gt;TimeZone&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;| &lt;code&gt;AT TIME ZONE 'X'&lt;/code&gt; | Reads the value as local time in X, returns &lt;code&gt;timestamptz&lt;/code&gt; | Returns &lt;code&gt;timestamp&lt;/code&gt;: the clock in X at that instant |&lt;/p&gt;

&lt;p&gt;| &lt;code&gt;date_trunc('day', v)&lt;/code&gt; | Taken at face value; no zone argument allowed | Midnight in the session zone, or in a zone you pass as the third argument |&lt;/p&gt;

&lt;p&gt;| &lt;code&gt;EXTRACT(epoch FROM v)&lt;/code&gt; | Nominal seconds, treated as if the value were UTC | True seconds since 1970-01-01 00:00:00 UTC |&lt;/p&gt;

&lt;p&gt;| &lt;code&gt;generate_series&lt;/code&gt; with a day step | Fixed arithmetic on the clock fields | DST adjustments computed in the session zone or an optional zone argument |&lt;/p&gt;

&lt;p&gt;| Can store a nonexistent or ambiguous local time | Yes, and cannot tell which instant was meant | No: it is already an instant |&lt;/p&gt;

&lt;h2&gt;
  
  
  The four classic bugs, with SQL
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Bug 1: the server TimeZone changes and every reading moves
&lt;/h3&gt;

&lt;p&gt;A session zone change makes &lt;code&gt;timestamptz&lt;/code&gt; display differently but leaves the instants alone. For a &lt;code&gt;timestamp&lt;/code&gt; column fed by &lt;code&gt;DEFAULT now()&lt;/code&gt; it is corruption: &lt;code&gt;now()&lt;/code&gt; returns &lt;code&gt;timestamp with time zone&lt;/code&gt;[2], so the zone-less column records a clock reading in whatever zone the writing session had, and rows from before and after the change sit on different baselines. The docs example of the flattening operation, with the session zone at &lt;code&gt;America/Los_Angeles&lt;/code&gt;[2]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'2001-02-16 20:38:40-05'&lt;/span&gt;
       &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'America/Denver'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- 2001-02-16 18:38:40   (a timestamp: the clock in Denver at that instant)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bug 2: DST gaps and overlaps
&lt;/h3&gt;

&lt;p&gt;A zone-less column can hold times that never happened or happened twice. In America/New_York clocks jump from 02:00 to 03:00 on 8 March 2026, so 02:30 does not exist, and on 1 November 2026 01:30 occurs twice. A &lt;code&gt;timestamp&lt;/code&gt; cannot say which; a &lt;code&gt;timestamptz&lt;/code&gt; is already an instant.&lt;/p&gt;

&lt;p&gt;Arithmetic carries the same trap. The docs show a day and 24 hours giving different answers across a DST change[1]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="s1"&gt;'2005-04-02 12:00:00-07'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="s1"&gt;'1 day'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- 2005-04-03 12:00:00-06&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="s1"&gt;'2005-04-02 12:00:00-07'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="s1"&gt;'24 hours'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- 2005-04-03 13:00:00-06&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bug 3: comparing now() with a timestamp column
&lt;/h3&gt;

&lt;p&gt;A filter like &lt;code&gt;WHERE expires_at &amp;gt; now()&lt;/code&gt; compares two instants when &lt;code&gt;expires_at&lt;/code&gt; is &lt;code&gt;timestamptz&lt;/code&gt;. On a &lt;code&gt;timestamp&lt;/code&gt; column Postgres converts one side using the session zone, so with UTC wall-clock values and an &lt;code&gt;Asia/Kolkata&lt;/code&gt; session the comparison is off by 5 hours 30 minutes. Fix the type. Until then compare against &lt;code&gt;now() AT TIME ZONE 'UTC'&lt;/code&gt;[2].&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug 4: AT TIME ZONE applied twice
&lt;/h3&gt;

&lt;p&gt;The operator flips direction depending on the input type, and it chains happily. The docs example[2]:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="s1"&gt;'2001-02-16 20:38:40'&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'Asia/Tokyo'&lt;/span&gt;
                                       &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'America/Chicago'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- 2001-02-16 05:38:40&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the mistake. On a &lt;code&gt;timestamptz&lt;/code&gt; column, &lt;code&gt;created_at AT TIME ZONE 'UTC' AT TIME ZONE 'Asia/Kolkata'&lt;/code&gt; first yields a UTC clock reading, then reads that as Kolkata local time and returns an instant 5 hours 30 minutes earlier than the original. To show a Kolkata clock reading, apply it once:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'Asia/Kolkata'&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;created_ist&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  date_trunc, generate_series, epoch and casts to date
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;date_trunc('day', ...)&lt;/code&gt; on a &lt;code&gt;timestamptz&lt;/code&gt; truncates in a particular zone: the session &lt;code&gt;TimeZone&lt;/code&gt; by default, or a zone you pass. On a &lt;code&gt;timestamp&lt;/code&gt; the value is taken at face value and a zone argument is not allowed[2]. Daily reports should name the zone:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;date_trunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'day'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Asia/Kolkata'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;day_ist&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;EXTRACT(epoch ...)&lt;/code&gt; shows the gap in one number: the docs example gives 982384720.12 for a zone-aware literal and 982355920.12 for the zone-less one, exactly 8 hours (28,800 seconds) apart, because a &lt;code&gt;timestamp&lt;/code&gt; is treated as if it were UTC[2]. Check values like these with the &lt;a href="https://dev.to/tools/timestamp-converter"&gt;Unix Timestamp Converter&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;generate_series&lt;/code&gt; on &lt;code&gt;timestamptz&lt;/code&gt; computes DST adjustments in the zone you name, or the session zone if you omit it[6]. Name it and a daily series stays on local midnight:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;generate_series&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s1"&gt;'2001-10-22 00:00 -04:00'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timestamptz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'2001-11-01 00:00 -05:00'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;timestamptz&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'1 day'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'America/New_York'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Casts like &lt;code&gt;created_at::date&lt;/code&gt; depend on the session zone, so write &lt;code&gt;(created_at AT TIME ZONE 'Asia/Kolkata')::date&lt;/code&gt; when you want a specific local date.&lt;/p&gt;

&lt;h2&gt;
  
  
  ORM and driver defaults in October 2026
&lt;/h2&gt;

&lt;p&gt;Defaults are split, and the split is where production mistakes start.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Default column type&lt;/th&gt;
&lt;th&gt;How to get timestamptz&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Prisma | &lt;code&gt;DateTime&lt;/code&gt; maps to &lt;code&gt;timestamp(3)&lt;/code&gt;[7] | &lt;code&gt;@db.Timestamptz(3)&lt;/code&gt; native type attribute[7] |&lt;/p&gt;

&lt;p&gt;| Drizzle | &lt;code&gt;timestamp()&lt;/code&gt; generates &lt;code&gt;timestamp&lt;/code&gt; without zone[8] | &lt;code&gt;timestamp({ withTimezone: true })&lt;/code&gt;[8] |&lt;/p&gt;

&lt;p&gt;| Django | The PostgreSQL backend stores datetimes as &lt;code&gt;timestamp with time zone&lt;/code&gt;, and time zone support is on by default in new projects[9] | Keep &lt;code&gt;USE_TZ = True&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;| Rails | "By default and for legacy reasons" &lt;code&gt;timestamp without time zone&lt;/code&gt;[10] | Set &lt;code&gt;datetime_type = :timestamptz&lt;/code&gt; in an &lt;code&gt;on_load(:active_record_postgresqladapter)&lt;/code&gt; hook, before generating new migrations[10] |&lt;/p&gt;

&lt;p&gt;| node-postgres | Parses &lt;code&gt;timestamp&lt;/code&gt; as local time of the Node process (&lt;code&gt;process.env.TZ&lt;/code&gt;)[11] | Use &lt;code&gt;timestamptz&lt;/code&gt; columns; &lt;code&gt;Date&lt;/code&gt; objects round-trip as instants |&lt;/p&gt;

&lt;p&gt;The Prisma fix is one attribute, &lt;code&gt;@db.Timestamptz(3)&lt;/code&gt;; the docs page lists the mapping but no standalone example, so check it on your version. In Drizzle: &lt;code&gt;timestamp('created_at', { withTimezone: true }).defaultNow()&lt;/code&gt;. The node-postgres default bites on servers whose &lt;code&gt;TZ&lt;/code&gt; is not UTC: a zone-less value written as UTC is parsed as local time, so a Node process in Mumbai reads every old &lt;code&gt;timestamp&lt;/code&gt; row 5 hours 30 minutes wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The rule, and the one exception
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The rule:&lt;/strong&gt; every column that records when something happened (created, paid, logged in, sent, expired) is &lt;code&gt;timestamptz&lt;/code&gt;. Write instants in, read instants out, and convert to a user's zone in the UI or in a query with an explicit &lt;code&gt;AT TIME ZONE&lt;/code&gt;. Django's docs agree: store in UTC, use local time only with users[9]. Set the connection zone to UTC in your pool config.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The exception:&lt;/strong&gt; a &lt;em&gt;future&lt;/em&gt; appointment tied to local clocks. "The 9:00 stand-up in Kolkata next March" must keep meaning 9:00 there even if rules change. The docs note that for future times Postgres assumes the latest known zone rules continue indefinitely[1]. If a government changes DST later, an instant you computed today does not move with it, but the person still expects 9:00 on the wall. So store the local reading plus the IANA name, and compute the instant when you need it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;appointments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt;          &lt;span class="nb"&gt;bigint&lt;/span&gt; &lt;span class="k"&gt;GENERATED&lt;/span&gt; &lt;span class="n"&gt;ALWAYS&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;local_start&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;-- 2027-03-03 09:00, wall clock on purpose&lt;/span&gt;
  &lt;span class="n"&gt;tz_name&lt;/span&gt;     &lt;span class="nb"&gt;text&lt;/span&gt;      &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;    &lt;span class="c1"&gt;-- 'Asia/Kolkata'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Validate zone names in the application, or with a trigger that looks them up in &lt;code&gt;pg_timezone_names&lt;/code&gt;, since a check constraint cannot contain a subquery. Compute the instant with &lt;code&gt;local_start AT TIME ZONE tz_name&lt;/code&gt;. Here &lt;code&gt;timestamp&lt;/code&gt; is the right type, because the whole point is a clock reading with a separate zone. If you schedule jobs from such rows, for example on a cron-driven agent like the one in &lt;a href="https://dev.to/blogs/personal-ai-agent-cloudflare-free-tier-2026"&gt;this Cloudflare free-tier build&lt;/a&gt;, compute the next UTC instant and store that too, then let the scheduler compare instants only.&lt;/p&gt;

&lt;h2&gt;
  
  
  Postgres 18 and time zones
&lt;/h2&gt;

&lt;p&gt;PostgreSQL 18 shipped on 25 September 2025 and its release notes change nothing about how &lt;code&gt;timestamp&lt;/code&gt; or &lt;code&gt;timestamptz&lt;/code&gt; store or convert values. One neighbouring item matters: the session's time zone abbreviations are now checked before the &lt;code&gt;timezone_abbreviations&lt;/code&gt; server variable[4]. Use full IANA names, since an abbreviation is only a fixed offset with no DST rules[1].&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating timestamp to timestamptz without downtime
&lt;/h2&gt;

&lt;p&gt;First decide what the old values mean: a column written by &lt;code&gt;DEFAULT now()&lt;/code&gt; under a UTC session holds UTC wall time, one written by an app in Mumbai holds IST. Use the zone the data was written in. Rows from a DST overlap cannot be repaired, because the information was never stored.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route A: in-place type change
&lt;/h3&gt;

&lt;p&gt;An &lt;code&gt;ALTER COLUMN ... TYPE&lt;/code&gt; takes an &lt;code&gt;ACCESS EXCLUSIVE&lt;/code&gt; lock unless the docs say otherwise, and normally rewrites the table and its indexes, needing up to twice the disk space[3]. The exception is a type change with no content change on a binary-coercible pair. PostgreSQL 12 added one for this exact pair: changing between &lt;code&gt;timestamp&lt;/code&gt; and &lt;code&gt;timestamptz&lt;/code&gt; avoids a table rewrite when the session zone is UTC, because the two types are binary compatible in UTC[5]. Indexes still rebuild unless the system can verify the new index is logically equivalent[3].&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;LOCAL&lt;/span&gt; &lt;span class="n"&gt;lock_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'3s'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;LOCAL&lt;/span&gt; &lt;span class="n"&gt;TimeZone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'UTC'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;TYPE&lt;/span&gt; &lt;span class="n"&gt;timestamptz&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ANALYZE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two cautions. I omitted &lt;code&gt;USING&lt;/code&gt; on purpose: the release note describes the plain type change, and I have not confirmed that &lt;code&gt;USING created_at AT TIME ZONE 'UTC'&lt;/code&gt; keeps the no-rewrite path. Test it on a copy and compare &lt;code&gt;pg_relation_filenode('events')&lt;/code&gt; before and after; a changed number means a rewrite happened. And the ALTER docs say a type change removes column statistics, so run &lt;code&gt;ANALYZE&lt;/code&gt; afterwards[3]. The lock queues behind long transactions, so keep &lt;code&gt;lock_timeout&lt;/code&gt; short and retry.&lt;/p&gt;

&lt;h3&gt;
  
  
  Route B: new column, backfill, swap
&lt;/h3&gt;

&lt;p&gt;Use this when the data is not UTC, the table is huge, or even a short exclusive lock is unacceptable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- 1. new column&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;created_at_tz&lt;/span&gt; &lt;span class="n"&gt;timestamptz&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 2. keep new writes in sync&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;events_sync_created_at&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;trigger&lt;/span&gt;
&lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at_tz&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'UTC'&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;NEW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;events_sync_created_at&lt;/span&gt;
&lt;span class="k"&gt;BEFORE&lt;/span&gt; &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;OF&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;
&lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="k"&gt;EACH&lt;/span&gt; &lt;span class="k"&gt;ROW&lt;/span&gt; &lt;span class="k"&gt;EXECUTE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;events_sync_created_at&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;-- 3. backfill in batches (repeat with the next id range until done)&lt;/span&gt;
&lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;created_at_tz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;AT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="s1"&gt;'UTC'&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;50001&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;created_at_tz&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- 4. index the new column without blocking writes&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;CONCURRENTLY&lt;/span&gt; &lt;span class="n"&gt;events_created_at_tz_idx&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created_at_tz&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;'UTC'&lt;/code&gt; with the real source zone if the old values were local. The expression follows the docs: a zone-less value &lt;code&gt;AT TIME ZONE&lt;/code&gt; a zone yields a &lt;code&gt;timestamptz&lt;/code&gt; assuming the value was in that zone[2]. Keep batches small and pause if replication lag climbs. Once the null count reaches zero and the app reads the new column, swap in one short transaction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="k"&gt;LOCAL&lt;/span&gt; &lt;span class="n"&gt;lock_timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'3s'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;TRIGGER&lt;/span&gt; &lt;span class="n"&gt;events_sync_created_at&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;created_at_old&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;created_at_tz&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;events_created_at_tz_idx&lt;/span&gt; &lt;span class="k"&gt;RENAME&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;events_created_at_idx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;-- after a release or two with no readers of created_at_old:&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;created_at_old&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drop the trigger inside the same transaction as the rename, or it will start writing to a column that no longer means what it did. If the column had a default, the ALTER docs warn that a &lt;code&gt;USING&lt;/code&gt; expression is not applied to defaults, so drop the default, change the type, and set a new one[3]. For Route B, set &lt;code&gt;DEFAULT now()&lt;/code&gt; on the new column before the swap. Tidy long migrations with the &lt;a href="https://dev.to/tools/sql-formatter"&gt;SQL Formatter&lt;/a&gt; before review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Does timestamptz store the time zone?
&lt;/h3&gt;

&lt;p&gt;No. It stores a UTC instant. Input with a zone is converted to UTC, input without one is assumed to be in the session TimeZone, and the original zone is discarded. On output the value is converted into the current session zone, so what you see depends on the connection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is timestamptz bigger or slower than timestamp?
&lt;/h3&gt;

&lt;p&gt;No. Both are 8 bytes with 1 microsecond resolution and the same range of 4713 BC to 294276 AD. Storage and range give you no reason to pick the zone-less type.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did my timestamp column ignore the +02 offset?
&lt;/h3&gt;

&lt;p&gt;Because for a zone-less value Postgres silently ignores any time zone indication in the input. It reads the date and clock fields and drops the rest. Cast the literal as &lt;code&gt;timestamptz&lt;/code&gt;, or change the column type, if the offset should count.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I change timestamp to timestamptz without rewriting the table?
&lt;/h3&gt;

&lt;p&gt;On PostgreSQL 12 and later, yes in the narrow case where the session time zone is UTC and you change the type without altering the contents. Indexes may still rebuild, and the lock is still ACCESS EXCLUSIVE. For non-UTC data or very large tables, use the new-column route instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  When should I keep timestamp instead of timestamptz?
&lt;/h3&gt;

&lt;p&gt;For future local-time appointments, store the wall-clock &lt;code&gt;timestamp&lt;/code&gt; plus an IANA zone name such as Asia/Kolkata, and derive the instant when needed. For anything that records when an event actually happened, use &lt;code&gt;timestamptz&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/datatype-datetime.html" rel="noopener noreferrer"&gt;PostgreSQL docs: Date/Time Types, sections 8.5.1.3 (#DATATYPE-DATETIME-INPUT-TIME-STAMPS) and 8.5.3 (#DATATYPE-TIMEZONES) (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/functions-datetime.html" rel="noopener noreferrer"&gt;PostgreSQL docs: Date/Time Functions, #FUNCTIONS-DATETIME-ZONECONVERT, #FUNCTIONS-DATETIME-TRUNC, #FUNCTIONS-DATETIME-EXTRACT (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/sql-altertable.html" rel="noopener noreferrer"&gt;PostgreSQL docs: ALTER TABLE, #SQL-ALTERTABLE-DESC-SET-DATA-TYPE and #SQL-ALTERTABLE-NOTES (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/18/release-18.html" rel="noopener noreferrer"&gt;PostgreSQL 18 release notes, E.6 (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/12/release-12.html" rel="noopener noreferrer"&gt;PostgreSQL 12 release notes, E.23.3.1.4 General Performance (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.postgresql.org/docs/current/functions-srf.html#FUNCTIONS-SRF-SERIES" rel="noopener noreferrer"&gt;PostgreSQL docs: Set Returning Functions, Table 9.69 Series Generating Functions (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.prisma.io/docs/orm/reference/prisma-schema-reference" rel="noopener noreferrer"&gt;Prisma schema reference: PostgreSQL native type mapping for DateTime (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://orm.drizzle.team/docs/column-types/pg" rel="noopener noreferrer"&gt;Drizzle ORM: PostgreSQL column types, timestamp (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.djangoproject.com/en/stable/topics/i18n/timezones/" rel="noopener noreferrer"&gt;Django docs: Time zones (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://guides.rubyonrails.org/active_record_postgresql.html" rel="noopener noreferrer"&gt;Rails Guides: Active Record and PostgreSQL, datetime types (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://node-postgres.com/features/types" rel="noopener noreferrer"&gt;node-postgres: data types (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Every product mentioned is available at wowhow.cloud — pay once, ship forever.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/postgres-timestamp-vs-timestamptz-rule-bugs-migration-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>postgrestimestamp</category>
      <category>timestamptzmigration</category>
      <category>attime</category>
      <category>prismatimestamptz</category>
    </item>
    <item>
      <title>Self-Hosted ngrok Alternatives 2026: Tunnel, frp, Tailscale</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Fri, 16 Oct 2026 07:15:44 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/self-hosted-ngrok-alternatives-2026-tunnel-frp-tailscale-55ig</link>
      <guid>https://dev.to/akaranjkar08/self-hosted-ngrok-alternatives-2026-tunnel-frp-tailscale-55ig</guid>
      <description>&lt;p&gt;&lt;strong&gt;If you only need a stable public URL for webhooks or a demo, Cloudflare Tunnel on a domain you own is the best free ngrok replacement in 2026, and frp on a $4 VPS is the best one you fully control.&lt;/strong&gt; ngrok's free plan is now $0 with 1 GB of data transfer out, 20,000 HTTP requests a month, 3 online endpoints and a single dev domain[1]. That is enough for a weekend of Stripe testing and not enough for a home-lab service. Tailscale Funnel is the fastest one-liner but limits you to your &lt;code&gt;ts.net&lt;/code&gt; name. rathole and bore are TCP-level tools, sish is SSH with HTTP routing, and Pangolin is a full zero-trust platform. Below: one comparison table, three working recipes, the webhook pattern, security rules, and when paying ngrok is the right call.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Need HTTP on your own hostname, free, no VPS: Cloudflare Tunnel (needs a domain on Cloudflare).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Need it in 30 seconds with no domain: &lt;code&gt;tailscale funnel 3000&lt;/code&gt; or a Cloudflare quick tunnel. Both change what the URL looks like, and quick tunnels are for testing only.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Need raw TCP or UDP, or full control: frp on a small VPS, or rathole for a lighter Rust binary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Need identity-aware access, SSO and per-resource rules: Pangolin, self-hosted or cloud.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pay ngrok when the tunnel is a work tool for a team and an hour of your time costs more than $10.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What ngrok's free plan actually gives you in October 2026
&lt;/h2&gt;

&lt;p&gt;The free plan includes $5 of one-time usage credit, then hard quotas[1][2]:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;1 GB data transfer out and 20,000 HTTP requests per month&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;5,000 TCP connections a month, with a rate cap of 100 TCP connections per minute&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;3 online endpoints, 3 concurrent agents, 1 user&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;One automatically assigned development domain, no custom domains&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No TLS endpoints, and an interstitial warning page shown to browser traffic&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The interstitial is the part that bites demos. Visitors click "Visit" once, which sets a cookie for 7 days. API callers such as webhook senders are not affected, and you can skip it with the &lt;code&gt;ngrok-skip-browser-warning&lt;/code&gt; header[2]. Custom domains start on Pay-as-you-go at $20 a month plus usage. Hobbyist is $10 a month[1].&lt;/p&gt;

&lt;p&gt;One more reason to leave: Razorpay's webhook docs say many common tunneling services are blacklisted for delivery and suggest zrok instead[9]. A tunnel on your own domain sidesteps that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;You need&lt;/th&gt;
&lt;th&gt;TLS&lt;/th&gt;
&lt;th&gt;Custom domain&lt;/th&gt;
&lt;th&gt;Protocols&lt;/th&gt;
&lt;th&gt;Auth in front&lt;/th&gt;
&lt;th&gt;Free-tier limits&lt;/th&gt;
&lt;th&gt;Setup&lt;/th&gt;
&lt;th&gt;Upkeep&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| ngrok Free | Account | Managed | No (one dev domain) | HTTP/S, TCP | Traffic policy, 3 OAuth MAU | 1 GB, 20k req, 3 endpoints | Minutes | None |&lt;/p&gt;

&lt;p&gt;| Cloudflare Tunnel | Free account + domain on Cloudflare | Managed at Cloudflare edge | Yes | HTTP, SSH, RDP and other protocols per docs | Cloudflare Access policies, service tokens | No bandwidth quota stated in the docs I read | 10 minutes | Keep &lt;code&gt;cloudflared&lt;/code&gt; updated |&lt;/p&gt;

&lt;p&gt;| Cloudflare quick tunnel | Nothing | Managed | No, random hostname | HTTP | Optional email allowlist | 200 in-flight requests, no SSE, no uptime guarantee | 10 seconds | None, not for production |&lt;/p&gt;

&lt;p&gt;| Tailscale Funnel | Tailscale account, MagicDNS, HTTPS on | Managed certs | No, &lt;code&gt;tailnet.ts.net&lt;/code&gt; names only | HTTPS, TCP with TLS | Tailscale ACL controls who can enable it | Non-configurable bandwidth limits; ports 443, 8443, 10000 | 2 minutes | Low |&lt;/p&gt;

&lt;p&gt;| frp | VPS + domain | You (Caddy or similar) | Yes | TCP, UDP, HTTP, HTTPS, P2P mode | Token between client and server; HTTP auth is your proxy | Your VPS bandwidth | 30 minutes | Patch VPS and frp |&lt;/p&gt;

&lt;p&gt;| rathole | VPS | Optional TLS or Noise transport | n/a, TCP-level | TCP, UDP; HTTP vhosts not documented | Per-service token | Your VPS bandwidth | 20 minutes | Low |&lt;/p&gt;

&lt;p&gt;| bore | VPS (or bore.pub) | None by default | n/a | TCP only | Optional shared secret (handshake only) | Your VPS bandwidth | 5 minutes | Low |&lt;/p&gt;

&lt;p&gt;| sish | VPS + domain | Flag-enabled HTTPS, certs from a directory | Yes | HTTP/WS, TCP, TCP aliases, SNI | SSH keys or password | Your VPS bandwidth | 30 minutes | Medium |&lt;/p&gt;

&lt;p&gt;| Pangolin | VPS (self-host) or Pangolin Cloud | Managed by the stack | Yes | HTTPS proxy, plus SSH, RDP, VNC and private ranges | Built-in SSO, roles, PIN, email OTP, geoblocking | Community Edition AGPL-3, free; Enterprise free under $100K revenue[8] | 1 hour | Highest |&lt;/p&gt;

&lt;p&gt;Sources for the rows: Cloudflare[3][4], Tailscale[5], frp[6], rathole, bore and sish READMEs[7], Pangolin[8]. I did not benchmark latency. Every tool in the table adds a hop, and a tunnel that terminates at a nearby edge or VPS will feel faster than one routed across a continent. Test with your own region.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 1: Cloudflare Tunnel with a named tunnel and config.yml
&lt;/h2&gt;

&lt;p&gt;You need a domain whose DNS is on Cloudflare and &lt;code&gt;cloudflared&lt;/code&gt; installed (&lt;code&gt;brew install cloudflared&lt;/code&gt; on macOS; the image is &lt;code&gt;cloudflare/cloudflared&lt;/code&gt; on Docker Hub[3]). The connector opens outbound connections only, so you can block all inbound traffic at the firewall[4]. Allow outbound port 7844 to Cloudflare[3].&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;# 1. Authenticate this machine&lt;/span&gt;
cloudflared tunnel login

&lt;span class="c"&gt;# 2. Create the tunnel (writes a UUID.json credentials file)&lt;/span&gt;
cloudflared tunnel create dev-tunnel

&lt;span class="c"&gt;# 3. Point a hostname at it&lt;/span&gt;
cloudflared tunnel route dns dev-tunnel hooks.example.com

&lt;span class="c"&gt;# 4. Run it&lt;/span&gt;
cloudflared tunnel run dev-tunnel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put the settings in &lt;code&gt;~/.cloudflared/config.yml&lt;/code&gt; so step 4 needs no flags. The documented format is a &lt;code&gt;url&lt;/code&gt; for the origin, the tunnel UUID and the credentials file[3]:&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;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;
&lt;span class="na"&gt;tunnel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;6ff42ae2-765d-4adf-8112-31c55c1551ef&lt;/span&gt;
&lt;span class="na"&gt;credentials-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/root/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace the UUID with the one printed in step 2. If the file lives elsewhere, add &lt;code&gt;--config /path/to/config.yml&lt;/code&gt; before &lt;code&gt;run&lt;/code&gt;. For a no-account test, &lt;code&gt;cloudflared tunnel --url http://localhost:8080&lt;/code&gt; starts a quick tunnel. Cloudflare's docs call those "for testing and development", with a 200 in-flight request cap, no Server-Sent Events and a hostname that changes every run[3]. Do not point a payment provider at one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 2: frp on a $4 VPS with TLS from Caddy
&lt;/h2&gt;

&lt;p&gt;frp supports TCP, UDP, HTTP and HTTPS forwarding by domain[6]. The layout: frps listens for clients on 7000 and for HTTP on 8080. Caddy owns 80 and 443, gets a certificate, and proxies to 8080. Close 8080 in the firewall so only Caddy reaches it. Point an A record for &lt;code&gt;hooks.example.com&lt;/code&gt; at the VPS first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/frp/frps.toml  (on the VPS)&lt;/span&gt;
&lt;span class="py"&gt;bindPort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7000&lt;/span&gt;
&lt;span class="py"&gt;vhostHTTPPort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;
&lt;span class="py"&gt;auth.method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"token"&lt;/span&gt;
&lt;span class="py"&gt;auth.token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"replace-with-a-long-random-string"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# frpc.toml  (on your laptop)&lt;/span&gt;
&lt;span class="py"&gt;serverAddr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"203.0.113.10"&lt;/span&gt;
&lt;span class="py"&gt;serverPort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7000&lt;/span&gt;
&lt;span class="py"&gt;auth.method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"token"&lt;/span&gt;
&lt;span class="py"&gt;auth.token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"replace-with-a-long-random-string"&lt;/span&gt;

&lt;span class="nn"&gt;[[proxies]]&lt;/span&gt;
&lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"webhooks"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http"&lt;/span&gt;
&lt;span class="py"&gt;localPort&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;span class="py"&gt;customDomains&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"hooks.example.com"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/caddy/Caddyfile  (on the VPS)
&lt;/span&gt;&lt;span class="n"&gt;hooks&lt;/span&gt;.&lt;span class="n"&gt;example&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt; {
    &lt;span class="n"&gt;reverse_proxy&lt;/span&gt; &lt;span class="m"&gt;127&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;0&lt;/span&gt;.&lt;span class="m"&gt;1&lt;/span&gt;:&lt;span class="m"&gt;8080&lt;/span&gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start with &lt;code&gt;frps -c /etc/frp/frps.toml&lt;/code&gt; and &lt;code&gt;frpc -c frpc.toml&lt;/code&gt;, then &lt;code&gt;sudo ufw allow 80,443,7000/tcp&lt;/code&gt; and nothing else public. The client token is the same value on both sides[6]. The Caddy block is my config, not from the frp docs, and Caddy fetches and renews the certificate on its own. Add &lt;code&gt;basic_auth&lt;/code&gt; inside the block if the endpoint is a human-facing dashboard. For a quick sanity check, run &lt;code&gt;curl -i https://hooks.example.com/health&lt;/code&gt; with your app up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 3: Tailscale Funnel in one line
&lt;/h2&gt;

&lt;p&gt;Funnel needs Tailscale 1.38.3 or later, MagicDNS and HTTPS certificates enabled for the tailnet, and a &lt;code&gt;funnel&lt;/code&gt; node attribute in the policy file. It is included on all plans and still labeled beta[5]. The first run walks you through enabling it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tailscale funnel 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The public name is under your &lt;code&gt;tailnet-name.ts.net&lt;/code&gt; domain, on port 443, 8443 or 10000 only, and traffic must be TLS. Bandwidth limits exist and you cannot change them[5]. By default every tailnet member can use Funnel; Owners, Admins and Network admins can restrict it with the &lt;code&gt;funnel&lt;/code&gt; attribute. A port cannot serve privately and publicly at once, so the latest of &lt;code&gt;serve&lt;/code&gt; and &lt;code&gt;funnel&lt;/code&gt; wins. You cannot bring &lt;code&gt;hooks.example.com&lt;/code&gt;, which makes Funnel a good demo tool and a mediocre webhook endpoint if your provider wants an allowlisted domain.&lt;/p&gt;

&lt;h2&gt;
  
  
  The webhook pattern: one stable URL, verify the signature, replay
&lt;/h2&gt;

&lt;p&gt;Stripe, Razorpay and GitHub all need a public URL, and they retry. Stripe tells you to return a 200 quickly and do slow work asynchronously[10]. The pattern that survives restarts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Run a named tunnel or frp host so the URL never changes. Register it once in each dashboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verify the signature on the raw body, never the parsed JSON. Stripe sends &lt;code&gt;Stripe-Signature&lt;/code&gt;[10], GitHub sends &lt;code&gt;X-Hub-Signature-256&lt;/code&gt; as an HMAC-SHA256 hex digest prefixed with &lt;code&gt;sha256=&lt;/code&gt;[11], and Razorpay sends &lt;code&gt;X-Razorpay-Signature&lt;/code&gt; and says not to parse the body before verifying[9].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep payloads from failed deliveries and replay them at localhost. Stripe's CLI can also skip the tunnel entirely: &lt;code&gt;stripe listen --forward-to localhost:4242/webhook&lt;/code&gt; and &lt;code&gt;stripe trigger payment_intent.succeeded&lt;/code&gt;[10].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rebuild a failed request as code with the &lt;a href="https://dev.to/tools/curl-to-code"&gt;cURL to code converter&lt;/a&gt; and fire it at your handler.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A tunnel gives your laptop a public face, so treat the path as hostile. A public webhook route accepts POSTs from anyone, and only the signature check separates Stripe from a stranger.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security notes before you expose anything
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expose one route, not the machine.&lt;/strong&gt; Point the tunnel at the webhook handler's port, not at a dev server that also serves an admin panel, a debugger or &lt;code&gt;/_next&lt;/code&gt; internals.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Never tunnel an unauthenticated admin UI.&lt;/strong&gt; Put identity in front. With Cloudflare, an Access policy denies everyone by default unless an Allow policy matches. Service Auth with a service token covers non-human callers[12]. Tailscale restricts who can switch on Funnel. Pangolin gives per-resource roles, PIN codes and email OTP[8].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rate-limit at the edge or the proxy.&lt;/strong&gt; Caddy needs a plugin for it; Cloudflare has rules on its side. Without a cap, a bot can fill your tunnel and your logs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treat bore's secret as a handshake lock only.&lt;/strong&gt; The README says nothing beyond the handshake is encrypted by default[7]. Run TLS inside the tunnel or choose a different tool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rotate tokens.&lt;/strong&gt; A leaked frp token lets anyone register proxies on your server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kill it when done.&lt;/strong&gt; A tunnel left running over a weekend is an open door. Run tunnels through &lt;code&gt;systemd&lt;/code&gt; or a Compose service you can stop; the &lt;a href="https://dev.to/blogs/docker-compose-production-nodejs-redis-postgres-2026"&gt;Docker Compose production guide&lt;/a&gt; shows the pattern.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using a tunnel to reach an agent's callback or an MCP server raises the stakes, since the caller can trigger actions. The &lt;a href="https://dev.to/blogs/claude-managed-agents-self-hosted-sandbox-mcp-tunnels-enterprise-guide-2026"&gt;Claude Managed Agents tunnels guide&lt;/a&gt; covers that case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking one, and when to just pay ngrok
&lt;/h2&gt;

&lt;p&gt;Webhook testing on a domain you own: Cloudflare Tunnel. A TCP service such as SSH, Postgres or a game server: frp or rathole on a VPS. A one-off demo to a colleague: Funnel or a quick tunnel. Zero-trust access for a family or team homelab: Pangolin, accepting the heavier install.&lt;/p&gt;

&lt;p&gt;Pay ngrok when setup time costs more than the plan. Hobbyist at $10 a month removes the interstitial and fits one person doing steady client demos[1]. Pay-as-you-go at $20 plus usage buys custom domains for a team that does not want to run a VPS[1]. I would pay before I ran frp for a team of five who rarely touch infrastructure.&lt;/p&gt;

&lt;p&gt;One alternative needs no tunnel at all: if the webhook target is a bot or a small API, deploy it as a Worker and register the Worker URL. The &lt;a href="https://dev.to/blogs/personal-ai-agent-cloudflare-free-tier-2026"&gt;personal AI agent on the Cloudflare free tier&lt;/a&gt; post does this for a Telegram webhook, and the &lt;a href="https://dev.to/blogs/cloudflare-workers-guide-2026-build-deploy-scale-edge-functions-free"&gt;Cloudflare Workers guide&lt;/a&gt; covers the deployment side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is Cloudflare Tunnel really free?
&lt;/h3&gt;

&lt;p&gt;The tunnel docs I read do not state a price or a bandwidth quota, and the pricing page did not load, so check the current Zero Trust plan before relying on it. You do need a domain on Cloudflare for named tunnels. Quick tunnels need no account but are limited to testing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can Tailscale Funnel use my own domain?
&lt;/h3&gt;

&lt;p&gt;No. Funnel only serves DNS names under your tailnet domain, &lt;code&gt;tailnet-name.ts.net&lt;/code&gt;, on ports 443, 8443 and 10000.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which tool handles UDP?
&lt;/h3&gt;

&lt;p&gt;frp lists UDP support, and rathole supports UDP services with &lt;code&gt;type = "udp"&lt;/code&gt; on the client. bore is TCP only. Cloudflare's tunnel overview does not mention UDP, so test before assuming it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is the cheapest way to get a stable webhook URL?
&lt;/h3&gt;

&lt;p&gt;A named Cloudflare Tunnel on a domain you already own costs nothing beyond the domain. If you want the box under your control, frp plus Caddy runs on a $4 VPS.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I still need a tunnel for Stripe testing?
&lt;/h3&gt;

&lt;p&gt;Not for development. &lt;code&gt;stripe listen --forward-to&lt;/code&gt; pushes events to localhost without a public URL. You need a public endpoint when a provider has no CLI forwarder, as with GitHub or Razorpay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://ngrok.com/pricing" rel="noopener noreferrer"&gt;ngrok pricing (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://ngrok.com/docs/pricing-limits/free-plan-limits/" rel="noopener noreferrer"&gt;ngrok: free plan limits (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/" rel="noopener noreferrer"&gt;Cloudflare Tunnel docs: overview, locally-managed tunnels, quick tunnels, downloads (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.cloudflare.com/cloudflare-one/networks/connectors/cloudflare-tunnel/get-started/create-remote-tunnel/" rel="noopener noreferrer"&gt;Cloudflare: create a remotely-managed tunnel (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://tailscale.com/kb/1223/funnel" rel="noopener noreferrer"&gt;Tailscale: Funnel (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/fatedier/frp" rel="noopener noreferrer"&gt;fatedier/frp README (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/rathole-org/rathole" rel="noopener noreferrer"&gt;rathole&lt;/a&gt;, &lt;a href="https://github.com/ekzhang/bore" rel="noopener noreferrer"&gt;bore&lt;/a&gt; and &lt;a href="https://github.com/antoniomika/sish" rel="noopener noreferrer"&gt;sish&lt;/a&gt; READMEs (accessed 16 October 2026)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/fosrl/pangolin" rel="noopener noreferrer"&gt;fosrl/pangolin README (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://razorpay.com/docs/webhooks/validate-test/" rel="noopener noreferrer"&gt;Razorpay: validate and test webhooks (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.stripe.com/webhooks/quickstart" rel="noopener noreferrer"&gt;Stripe: set up and deploy a webhook (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries" rel="noopener noreferrer"&gt;GitHub: validating webhook deliveries (accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  12. &lt;a href="https://developers.cloudflare.com/cloudflare-one/policies/access/" rel="noopener noreferrer"&gt;Cloudflare Access policies (accessed 16 October 2026)&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/self-hosted-ngrok-alternatives-cloudflare-tunnel-frp-tailscale-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ngrokalternatives</category>
      <category>selfhostedngrok</category>
      <category>cloudflaretunnel</category>
      <category>tailscalefunnel</category>
    </item>
    <item>
      <title>Claude Code Plugin Marketplace 2026: Package and Publish</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Fri, 16 Oct 2026 07:15:12 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/claude-code-plugin-marketplace-2026-package-and-publish-50nd</link>
      <guid>https://dev.to/akaranjkar08/claude-code-plugin-marketplace-2026-package-and-publish-50nd</guid>
      <description>&lt;p&gt;&lt;strong&gt;A Claude Code plugin is a directory that bundles skills, agents, hooks and MCP servers so Claude Code installs them as one unit, and a marketplace is a git repository with a &lt;code&gt;.claude-plugin/marketplace.json&lt;/code&gt; file that lists plugins.&lt;/strong&gt; Only &lt;code&gt;name&lt;/code&gt; is required in the plugin manifest. Only &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;owner&lt;/code&gt; and &lt;code&gt;plugins&lt;/code&gt; are required in the marketplace file. If the repository is private, the marketplace is private. I checked every command and field below against the current Claude Code docs and &lt;code&gt;claude plugin --help&lt;/code&gt; on version 2.1.299. Below: plugin vs skill vs MCP vs hook, the layout and manifest, plugin hooks vs &lt;code&gt;settings.json&lt;/code&gt; hooks, the marketplace schema, updates, team rollout, a security checklist, and a plugin you can publish in 15 minutes.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A plugin is packaging: skills, agents, hooks and MCP servers installed together under one name and version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;.claude-plugin/plugin.json&lt;/code&gt; holds only the manifest. Everything else sits at the plugin root.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Publish a repo with &lt;code&gt;.claude-plugin/marketplace.json&lt;/code&gt;. Users run &lt;code&gt;/plugin marketplace add owner/repo&lt;/code&gt;, then &lt;code&gt;/plugin install name@marketplace&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Updates arrive only when &lt;code&gt;version&lt;/code&gt; changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Teams: &lt;code&gt;extraKnownMarketplaces&lt;/code&gt; and &lt;code&gt;enabledPlugins&lt;/code&gt; in managed settings or the repo's &lt;code&gt;.claude/settings.json&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A plugin runs code as you. Read its hooks, &lt;code&gt;.mcp.json&lt;/code&gt; and &lt;code&gt;bin/&lt;/code&gt; before installing.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Plugin vs skill vs MCP server vs hook
&lt;/h2&gt;

&lt;p&gt;Skills, subagents, hooks and MCP servers all work on their own. A skill in &lt;code&gt;~/.claude/skills/&lt;/code&gt; is available in every project on your machine[1]. Make a plugin when you want several pieces installed together, shared with teammates, or released with versions. Plugin skills and agents get the plugin name as a prefix, so two plugins can each ship a &lt;code&gt;hello&lt;/code&gt; skill without colliding[2]. For the layer question itself, see &lt;a href="https://dev.to/blogs/mcp-vs-cli-vs-skills-agent-tool-layer-2026"&gt;MCP vs CLI vs skills&lt;/a&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Thing&lt;/th&gt;
&lt;th&gt;What it is&lt;/th&gt;
&lt;th&gt;Runs code?&lt;/th&gt;
&lt;th&gt;Where it lives&lt;/th&gt;
&lt;th&gt;Shareable as&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Skill | &lt;code&gt;SKILL.md&lt;/code&gt; instructions Claude loads when relevant, also runnable as a command | No, it steers Claude | &lt;code&gt;skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt; | A folder, or inside a plugin |&lt;/p&gt;

&lt;p&gt;| MCP server | Tool server Claude Code connects to | Yes, a stdio server is a process on your machine | &lt;code&gt;.mcp.json&lt;/code&gt; | Config file, or inside a plugin |&lt;/p&gt;

&lt;p&gt;| Hook | Command Claude Code runs at a lifecycle event | Yes, a shell command with your permissions | &lt;code&gt;settings.json&lt;/code&gt; or &lt;code&gt;hooks/hooks.json&lt;/code&gt; | Settings snippet, or inside a plugin |&lt;/p&gt;

&lt;p&gt;| Plugin | Directory that bundles any mix of the above with a manifest | If it contains hooks, MCP servers, monitors or &lt;code&gt;bin/&lt;/code&gt; | Plugin root, with optional &lt;code&gt;.claude-plugin/plugin.json&lt;/code&gt; | A marketplace entry, a zip, or &lt;code&gt;--plugin-dir&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;One cost: an enabled plugin is part of every session. The name and description of each skill, agent and command Claude can invoke on its own sit in context every turn, counting toward usage even when nothing from the plugin runs[1]. The &lt;a href="https://dev.to/tools/claude-max-api-credits-planner"&gt;Claude Max API credits planner&lt;/a&gt; shows what a heavier context footprint does to a monthly budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plugin directory layout and the manifest
&lt;/h2&gt;

&lt;p&gt;The layout is strict in one place. Put only &lt;code&gt;plugin.json&lt;/code&gt; inside &lt;code&gt;.claude-plugin/&lt;/code&gt;. Components saved there do not load[3]. Every other directory sits at the plugin root:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;deploy-tools/
├── .claude-plugin/
│   └── plugin.json
├── skills/
│   └── deploy/
│       └── SKILL.md
├── agents/
│   └── reviewer.md
├── hooks/
│   └── hooks.json
├── bin/               (on the Bash tool PATH while enabled)
└── .mcp.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The manifest is optional. Without it, Claude Code loads components from these default locations and takes the name from the marketplace entry or directory[3]. Write one for metadata, a version, or components outside the defaults. Fields worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;name&lt;/code&gt;: the only required key. Kebab-case. Every component is namespaced under it, so agent &lt;code&gt;reviewer&lt;/code&gt; in plugin &lt;code&gt;deploy-tools&lt;/code&gt; appears as &lt;code&gt;deploy-tools:reviewer&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;version&lt;/code&gt;: a string, not checked against semver. Setting it pins users until you change it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;description&lt;/code&gt;, &lt;code&gt;author&lt;/code&gt; (object, &lt;code&gt;name&lt;/code&gt; required), &lt;code&gt;homepage&lt;/code&gt; (must parse as a URL or the plugin fails to load), &lt;code&gt;repository&lt;/code&gt;, &lt;code&gt;license&lt;/code&gt;, &lt;code&gt;keywords&lt;/code&gt;, &lt;code&gt;displayName&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;skills&lt;/code&gt;, &lt;code&gt;commands&lt;/code&gt;, &lt;code&gt;agents&lt;/code&gt;, &lt;code&gt;hooks&lt;/code&gt;, &lt;code&gt;mcpServers&lt;/code&gt;: paths or inline config for components outside the defaults. Paths start with &lt;code&gt;./&lt;/code&gt; and stay inside the plugin root.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;dependencies&lt;/code&gt; and &lt;code&gt;userConfig&lt;/code&gt; (values Claude Code prompts for, with &lt;code&gt;sensitive: true&lt;/code&gt; keeping secrets out of &lt;code&gt;settings.json&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skills live in &lt;code&gt;skills/&amp;lt;name&amp;gt;/SKILL.md&lt;/code&gt; and run as &lt;code&gt;/plugin-name:skill-name&lt;/code&gt;. Agents are Markdown files in &lt;code&gt;agents/&lt;/code&gt;. Hooks go in &lt;code&gt;hooks/hooks.json&lt;/code&gt;, MCP servers in &lt;code&gt;.mcp.json&lt;/code&gt;. A &lt;code&gt;CLAUDE.md&lt;/code&gt; at the plugin root is not loaded as context, so put instructions in a skill[3]. Names starting with &lt;code&gt;claude-&lt;/code&gt; or &lt;code&gt;anthropic-&lt;/code&gt; fail validation. An unknown top-level key is stripped with only a warning.&lt;/p&gt;

&lt;h2&gt;
  
  
  hooks/hooks.json vs settings.json hooks
&lt;/h2&gt;

&lt;p&gt;The event, matcher and handler nesting is identical. Two differences matter. A plugin hooks file wraps the event map in a top-level &lt;code&gt;"hooks"&lt;/code&gt; key, and a bare event map fails to load, while inline &lt;code&gt;hooks&lt;/code&gt; in &lt;code&gt;plugin.json&lt;/code&gt; have no wrapper[3]. And bundled scripts are referenced through &lt;code&gt;${CLAUDE_PLUGIN_ROOT}&lt;/code&gt;, which changes on every update (use &lt;code&gt;${CLAUDE_PLUGIN_DATA}&lt;/code&gt; for state that must survive). Plugin hooks merge with your user and project hooks[4]. Hooks have no prefix, so a hook migrated into a plugin but left in &lt;code&gt;settings.json&lt;/code&gt; runs twice[5].&lt;/p&gt;

&lt;h2&gt;
  
  
  The marketplace file
&lt;/h2&gt;

&lt;p&gt;A marketplace is a directory or repository with &lt;code&gt;.claude-plugin/marketplace.json&lt;/code&gt;. Required top-level keys are &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;owner&lt;/code&gt; (with &lt;code&gt;name&lt;/code&gt;) and &lt;code&gt;plugins&lt;/code&gt;. Each plugin entry needs &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;source&lt;/code&gt;[6].&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;"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;"team-tools"&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;"Plugins for my team"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"owner"&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;"Your Name"&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;"plugins"&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;"no-bypass"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./plugins/no-bypass"&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;"Blocks git --no-verify and teaches commit hygiene"&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 &lt;code&gt;source&lt;/code&gt; is a relative path from the marketplace root (the directory containing &lt;code&gt;.claude-plugin/&lt;/code&gt;, never with &lt;code&gt;..&lt;/code&gt;) or an object: &lt;code&gt;github&lt;/code&gt; (&lt;code&gt;repo&lt;/code&gt;, &lt;code&gt;ref&lt;/code&gt;, &lt;code&gt;sha&lt;/code&gt;), &lt;code&gt;url&lt;/code&gt;, &lt;code&gt;git-subdir&lt;/code&gt;, &lt;code&gt;npm&lt;/code&gt;, &lt;code&gt;archive&lt;/code&gt; (zip over HTTPS, optional &lt;code&gt;sha256&lt;/code&gt; pin) or &lt;code&gt;command&lt;/code&gt;[6]. Keep the entry &lt;code&gt;name&lt;/code&gt; identical to the one in the plugin's &lt;code&gt;plugin.json&lt;/code&gt;, or installing by the manifest name reports the plugin as not found[7]. Names like &lt;code&gt;claude-plugins-official&lt;/code&gt; and &lt;code&gt;claude-community&lt;/code&gt; are accepted only for marketplaces sourced from &lt;code&gt;github.com/anthropics/&lt;/code&gt;[6].&lt;/p&gt;

&lt;h3&gt;
  
  
  Install and manage
&lt;/h3&gt;

&lt;p&gt;Users register a marketplace once, then install by name. Inside a session:&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 your-org/your-marketplace
/plugin install no-bypass@team-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From a shell: &lt;code&gt;claude plugin marketplace add&lt;/code&gt; and &lt;code&gt;claude plugin install no-bypass@team-tools&lt;/code&gt;. The add command takes a GitHub &lt;code&gt;owner/repo&lt;/code&gt;, a git URL, a hosted &lt;code&gt;marketplace.json&lt;/code&gt; URL, or a local path. Append &lt;code&gt;#&amp;lt;ref&amp;gt;&lt;/code&gt; to pin a branch or tag. Shorthand always means github.com, so GitLab users need the full URL. A URL-hosted marketplace downloads only the JSON, so relative-path entries fail there[7].&lt;/p&gt;

&lt;h2&gt;
  
  
  Versioning and updates
&lt;/h2&gt;

&lt;p&gt;This is where people lose an afternoon. Users get a new copy only when the computed version changes. Set &lt;code&gt;"version": "1.0.0"&lt;/code&gt;, push ten commits, and &lt;code&gt;claude plugin update&lt;/code&gt; reports the plugin is already at the latest version[8]. Either bump &lt;code&gt;version&lt;/code&gt; on every release or omit it from both &lt;code&gt;plugin.json&lt;/code&gt; and the marketplace entry so the commit SHA decides. Never set it in both: &lt;code&gt;plugin.json&lt;/code&gt; wins silently[7].&lt;/p&gt;

&lt;p&gt;Auto-update is off by default and &lt;code&gt;marketplace.json&lt;/code&gt; has no field for it. Each user enables it under Marketplaces in &lt;code&gt;/plugin&lt;/code&gt;, or an admin sets &lt;code&gt;"autoUpdate": true&lt;/code&gt; in managed settings[7]. Otherwise users run &lt;code&gt;claude plugin update name@marketplace&lt;/code&gt;. Pin a release with &lt;code&gt;ref&lt;/code&gt; or a 40-character &lt;code&gt;sha&lt;/code&gt; on the entry. &lt;code&gt;claude plugin tag&lt;/code&gt; creates a &lt;code&gt;{name}--v{version}&lt;/code&gt; git tag[8]. Never rename a published plugin; add a &lt;code&gt;renames&lt;/code&gt; map to the marketplace instead[7].&lt;/p&gt;

&lt;h2&gt;
  
  
  Team distribution
&lt;/h2&gt;

&lt;p&gt;For a team, a private GitHub repository is enough: anyone who can clone it can install from it. Claude Code has no git token of its own and &lt;code&gt;marketplace.json&lt;/code&gt; has no credential field, so installs use the machine's git credentials. For HTTPS, &lt;code&gt;gh auth login&lt;/code&gt; then &lt;code&gt;gh auth setup-git&lt;/code&gt; stores one. Without a GitHub SSH key, set &lt;code&gt;CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1&lt;/code&gt;. The catch: auto-update against a private repo needs a stored credential, and a helper that has to prompt fails quietly[7].&lt;/p&gt;

&lt;p&gt;To register the marketplace for one repository, run &lt;code&gt;claude plugin marketplace add your-org/your-marketplace --scope project&lt;/code&gt; and commit the &lt;code&gt;.claude/settings.json&lt;/code&gt; it writes. It applies once a contributor trusts the folder. Company-wide, the verified setting names go in managed settings:&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;"extraKnownMarketplaces"&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;"team-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="nl"&gt;"source"&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;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"repo"&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-org/team-tools"&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;"autoUpdate"&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;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"enabledPlugins"&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;"no-bypass@team-tools"&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;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;Managed settings win over every other scope, so a user disabling the plugin does not stop it loading; &lt;code&gt;false&lt;/code&gt; in managed &lt;code&gt;enabledPlugins&lt;/code&gt; blocks a plugin everywhere[9]. &lt;code&gt;strictKnownMarketplaces&lt;/code&gt; (alias &lt;code&gt;allowedMarketplaces&lt;/code&gt;) is an allowlist, &lt;code&gt;blockedMarketplaces&lt;/code&gt; a blocklist checked first, and &lt;code&gt;disableSideloadFlags&lt;/code&gt; rejects &lt;code&gt;--plugin-dir&lt;/code&gt;. An empty allowlist blocks every source, official marketplace included, and any allowlist stops plugins under &lt;code&gt;~/.claude/skills/&lt;/code&gt; unless you add &lt;code&gt;{ "source": "skills-dir" }&lt;/code&gt;[9]. The aliases need v2.1.232 or later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The official marketplace and the world
&lt;/h2&gt;

&lt;p&gt;Claude Code registers the official marketplace (&lt;code&gt;claude-plugins-official&lt;/code&gt;) on first interactive start unless managed policy blocks it. Community and demo marketplaces are not added automatically[1]. To reach everyone, publish a public marketplace repo and share the two commands, or submit to Anthropic's directory at claude.ai/directory/manage (paid claude.ai plan required; it reaches Claude Code through account sync as &lt;code&gt;name@synced&lt;/code&gt;). The official marketplace takes no submissions through that portal[10]. Anthropic sorts marketplaces into official, community and third-party tiers by name, and says the name tells you who publishes the catalog, not what each plugin does[11].&lt;/p&gt;

&lt;h2&gt;
  
  
  Test locally before you publish
&lt;/h2&gt;

&lt;p&gt;Load a plugin for one session with &lt;code&gt;claude --plugin-dir ./my-plugin&lt;/code&gt; (repeatable, also accepts a &lt;code&gt;.zip&lt;/code&gt;). Point it at one plugin's root, not a marketplace root, or nothing loads and you get no error. After edits, run &lt;code&gt;/reload-plugins&lt;/code&gt;[2]. Then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;claude plugin validate ./my-plugin&lt;/code&gt; checks the manifest and every skill, agent and command frontmatter. Add &lt;code&gt;--strict&lt;/code&gt; in CI.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;claude plugin validate ./my-marketplace&lt;/code&gt; checks the JSON and each entry.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;claude plugin marketplace add ./my-marketplace&lt;/code&gt; and install from it. A relative path to a missing directory passes validation and fails at install.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;claude plugin details my-plugin&lt;/code&gt; prints the component inventory.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The docs name &lt;code&gt;CLAUDE_CONFIG_DIR&lt;/code&gt; as the configuration directory Claude Code uses in place of &lt;code&gt;~/.claude&lt;/code&gt;[7] but publish no isolated-install walkthrough, so try that on a scratch machine first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security checklist before installing a third-party plugin
&lt;/h2&gt;

&lt;p&gt;Anthropic's wording: a plugin can execute arbitrary code on your machine with your user privileges[11]. Hooks, monitors, MCP servers and LSP servers run outside the sandbox and your permission rules. Skills and agents enter context as instructions. Read a plugin like an install script. For the container side, see &lt;a href="https://dev.to/blogs/sandbox-claude-code-codex-docker-vs-gvisor-vs-microvm-2026"&gt;sandboxing Claude Code and Codex&lt;/a&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Source.&lt;/strong&gt; &lt;code&gt;claude plugin marketplace list&lt;/code&gt; prints where each marketplace came from.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hooks.&lt;/strong&gt; Read &lt;code&gt;hooks/hooks.json&lt;/code&gt; end to end. The details pane shows a hook exists, not what it runs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;MCP.&lt;/strong&gt; Read &lt;code&gt;.mcp.json&lt;/code&gt;: each server's command or URL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;bin/.&lt;/strong&gt; Everything there lands on the Bash tool's &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inventory.&lt;/strong&gt; &lt;code&gt;claude --plugin-dir &amp;lt;dir&amp;gt; plugin details &amp;lt;name&amp;gt;&lt;/code&gt; on a clone lists skills, agents, hooks with events, and servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Updates.&lt;/strong&gt; With auto-update on, reviewed files can change. Pin a &lt;code&gt;sha&lt;/code&gt; for marketplaces you do not control.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Uninstall with &lt;code&gt;claude plugin uninstall&lt;/code&gt; at the scope you installed; cached files stay under &lt;code&gt;~/.claude/plugins/cache/&lt;/code&gt; for 14 days[11].&lt;/p&gt;

&lt;h2&gt;
  
  
  A complete example in 15 minutes
&lt;/h2&gt;

&lt;p&gt;One repo, one marketplace, one plugin named &lt;code&gt;no-bypass&lt;/code&gt; with a skill and a PreToolUse hook that blocks &lt;code&gt;git ... --no-verify&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;team-tools/
├── .claude-plugin/
│   └── marketplace.json
└── plugins/
    └── no-bypass/
        ├── .claude-plugin/
        │   └── plugin.json
        ├── skills/
        │   └── commit-hygiene/
        │       └── SKILL.md
        ├── hooks/
        │   └── hooks.json
        └── scripts/
            └── block-no-verify.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;plugins/no-bypass/.claude-plugin/plugin.json&lt;/strong&gt;&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;"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;"no-bypass"&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;"Blocks git --no-verify and teaches commit hygiene"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&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;"Your Name"&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;&lt;strong&gt;plugins/no-bypass/skills/commit-hygiene/SKILL.md&lt;/strong&gt;&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="nn"&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;commit-hygiene&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;Commit rules for this repo. Use before running git commit.&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="s"&gt;Never bypass git hooks. If a pre-commit hook fails, read the output,&lt;/span&gt;
&lt;span class="s"&gt;fix the cause, and commit again. Do not pass --no-verify.&lt;/span&gt;
&lt;span class="s"&gt;Keep commits small.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;plugins/no-bypass/hooks/hooks.json&lt;/strong&gt; (note the top-level &lt;code&gt;"hooks"&lt;/code&gt; wrapper; exec form with &lt;code&gt;args&lt;/code&gt; keeps the path as a single argument)&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;"hooks"&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;"PreToolUse"&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;"matcher"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&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;"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;"command"&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;"bash"&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;"${CLAUDE_PLUGIN_ROOT}/scripts/block-no-verify.sh"&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="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;&lt;strong&gt;plugins/no-bypass/scripts/block-no-verify.sh&lt;/strong&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="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Reads the PreToolUse JSON on stdin. Exit 2 blocks the call and&lt;/span&gt;
&lt;span class="c"&gt;# shows stderr to Claude. Needs jq on PATH.&lt;/span&gt;
&lt;span class="nb"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.tool_input.command // ""'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-qE&lt;/span&gt; &lt;span class="s1"&gt;'git[[:space:]].*--no-verify'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Blocked: --no-verify skips git hooks. Fix the failing check instead."&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&amp;amp;2
  &lt;span class="nb"&gt;exit &lt;/span&gt;2
&lt;span class="k"&gt;fi

&lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a Bash call the hook receives JSON on stdin with the command in &lt;code&gt;tool_input.command&lt;/code&gt;. Exit code 2 blocks the call and shows stderr to Claude[4]. Use one blocking method per hook. The short flag &lt;code&gt;git commit -n&lt;/code&gt; does the same as &lt;code&gt;--no-verify&lt;/code&gt; and this regex misses it, so extend the pattern if that matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;.claude-plugin/marketplace.json&lt;/strong&gt; at the repo root is the one shown earlier. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude plugin validate ./team-tools
claude plugin validate ./team-tools/plugins/no-bypass &lt;span class="nt"&gt;--strict&lt;/span&gt;
claude &lt;span class="nt"&gt;--plugin-dir&lt;/span&gt; ./team-tools/plugins/no-bypass
git init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"no-bypass 1.0.0"&lt;/span&gt;
&lt;span class="c"&gt;# push to github.com/your-org/team-tools, then on any machine:&lt;/span&gt;
claude plugin marketplace add your-org/team-tools
claude plugin &lt;span class="nb"&gt;install &lt;/span&gt;no-bypass@team-tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;--plugin-dir&lt;/code&gt; session, ask Claude to run &lt;code&gt;git commit --no-verify -m test&lt;/code&gt;. The call is blocked and Claude sees your message. For a marketplace-ready example you can install and read, the &lt;a href="https://dev.to/product/opus-55-claude-code-plugin"&gt;Opus 5.5 Claude Code Plugin&lt;/a&gt; ships five guard hooks, effort presets and ten skills in exactly this layout; pair it with &lt;a href="https://dev.to/blogs/opus-5-5-claude-code-effort-settings-claude-md-rules-2026"&gt;the Opus 5.5 effort settings and CLAUDE.md rules&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do I need a plugin, or is a skill enough?
&lt;/h3&gt;

&lt;p&gt;A skill is enough while it serves you or one project. Make a plugin to install several components together, share them across projects, or release versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why did my users not get my update?
&lt;/h3&gt;

&lt;p&gt;The version did not change. With &lt;code&gt;version&lt;/code&gt; set in &lt;code&gt;plugin.json&lt;/code&gt;, &lt;code&gt;claude plugin update&lt;/code&gt; reports already latest until you bump it. Or omit it so the commit SHA decides.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I roll a plugin out to a whole team?
&lt;/h3&gt;

&lt;p&gt;Private repo, then &lt;code&gt;extraKnownMarketplaces&lt;/code&gt; and &lt;code&gt;enabledPlugins&lt;/code&gt; in the repo's &lt;code&gt;.claude/settings.json&lt;/code&gt; or in managed settings. Repository entries apply after each contributor trusts the folder. Managed settings cannot be overridden.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is a plugin from an official or community marketplace safe?
&lt;/h3&gt;

&lt;p&gt;Not automatically. Anthropic says a plugin can run code with your user privileges. Review hooks, MCP config and &lt;code&gt;bin/&lt;/code&gt; whatever the tier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a plugin hook replace a settings.json hook?
&lt;/h3&gt;

&lt;p&gt;Yes, with the same event and matcher structure, wrapped in a top-level &lt;code&gt;"hooks"&lt;/code&gt; key. Remove the original afterwards or it runs twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins" rel="noopener noreferrer"&gt;Plugins overview&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/create" rel="noopener noreferrer"&gt;Create a plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins-reference" rel="noopener noreferrer"&gt;Plugin manifest reference&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/hooks" rel="noopener noreferrer"&gt;Hooks reference&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/create#convert-an-existing-claude-setup" rel="noopener noreferrer"&gt;Convert an existing .claude/ setup&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/marketplace-reference" rel="noopener noreferrer"&gt;Marketplace reference&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/host-marketplace" rel="noopener noreferrer"&gt;Host and maintain a marketplace&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/publish" rel="noopener noreferrer"&gt;Publish and distribute a plugin&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/org" rel="noopener noreferrer"&gt;Manage plugins for your organization&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/publish#submit-to-anthropics-directory" rel="noopener noreferrer"&gt;Submit to Anthropic's directory&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/plugins/security" rel="noopener noreferrer"&gt;Plugin security and trust&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Every product mentioned is available at wowhow.cloud — pay once, ship forever.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/claude-code-plugin-marketplace-package-publish-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>claudecode</category>
      <category>marketplacejson</category>
      <category>pluginjson</category>
      <category>extraknownmarketplac</category>
    </item>
    <item>
      <title>Suno Songs on YouTube 2026: Content ID and Disclosure</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Thu, 15 Oct 2026 23:39:08 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/suno-songs-on-youtube-2026-content-id-and-disclosure-40p7</link>
      <guid>https://dev.to/akaranjkar08/suno-songs-on-youtube-2026-content-id-and-disclosure-40p7</guid>
      <description>&lt;p&gt;&lt;strong&gt;As of October 2026, a Suno song can earn money on YouTube only if you made it on a Pro or Premier plan, and YouTube asks you to disclose it as AI whenever the music is the main focus of the video.&lt;/strong&gt; Suno's terms (updated 10 August 2026) assign you the output you downloaded while subscribed, but state that Suno makes no promise any copyright will vest in it.&lt;a href="https://suno.com/terms" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; That gap is why Content ID registration is shaky: YouTube requires exclusive rights, and Suno also says output may not be unique across users. Below: the ownership rules by plan, what the disclosure tick does, who can claim Content ID, how to dispute a claim (30 days), what the Partner Program says about mass-produced AI music, a release checklist, and three scenarios with outcomes. Everything is dated, and what I could not verify is left out.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Free-plan songs are personal and non-commercial only. Pro and Premier songs downloaded while subscribed carry commercial rights.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tick the YouTube Studio AI disclosure when AI music is the main focus of the video. Disclosure alone does not limit reach or monetisation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Content ID needs exclusive rights. A Suno output that is not unique to you is a weak candidate; skip it unless your distributor says yes in writing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A Content ID dispute gives the claimant 30 days to respond. A rejected dispute can end in a copyright strike if a valid removal request follows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Channels of templated, near-identical AI tracks over still images risk the Partner Program "inauthentic content" rule.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who owns a Suno song in October 2026
&lt;/h2&gt;

&lt;p&gt;Ownership depends on the plan you were on when you made and downloaded the track. Two sources agree: the terms of service and Suno's help centre.&lt;/p&gt;

&lt;h3&gt;
  
  
  Free plan
&lt;/h3&gt;

&lt;p&gt;The terms contain no assignment of output to free users and limit use to "lawful, personal and non-commercial purposes."&lt;a href="https://suno.com/terms" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; Suno's help article is blunter: free-plan songs "cannot be monetized."&lt;a href="https://help.suno.com/en/articles/9601601" rel="noopener noreferrer"&gt;[2]&lt;/a&gt; That includes YouTube ad revenue. Subscribing later does not retroactively license earlier songs.&lt;a href="https://help.suno.com/en/articles/2410177" rel="noopener noreferrer"&gt;[3]&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pro and Premier
&lt;/h3&gt;

&lt;p&gt;The terms say Suno "hereby assigns to you all of its right, title and interest in and to any Output owned by Suno," and that you may not commercially exploit output you have not downloaded through an approved channel. Commercial rights on downloaded songs are described as perpetual and survive cancelling.&lt;a href="https://suno.com/terms" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; The help centre says songs downloaded while subscribed are "granted commercial use rights" and can be distributed to streaming platforms.&lt;a href="https://help.suno.com/en/articles/9601665" rel="noopener noreferrer"&gt;[4]&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The catch: ownership is not copyright
&lt;/h3&gt;

&lt;p&gt;The same help article warns that commercial rights do not guarantee copyright protection. Suno's copyright answer says music made 100% with AI would not qualify in the US, and that writing the prompt "does not constitute the creation of the song." Lyrics you wrote yourself may be registrable.&lt;a href="https://help.suno.com/en/articles/2746945" rel="noopener noreferrer"&gt;[5]&lt;/a&gt; The terms add that output "may not be unique across users." Hold on to that sentence. It is the reason the Content ID section below ends where it does.&lt;/p&gt;

&lt;h2&gt;
  
  
  The altered or synthetic content disclosure
&lt;/h2&gt;

&lt;p&gt;YouTube's help page lists "creates music that's the main focus of the video" among the realistic-content triggers and gives "AI generated music" as an example. As of October 2026 you answer the disclosure question in YouTube Studio at upload.&lt;a href="https://support.google.com/youtube/answer/14328491" rel="noopener noreferrer"&gt;[6]&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Must tick:&lt;/strong&gt; a Suno track as the song people came to hear, a lyric video, a visualiser for an AI song, an AI album upload.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No tick needed:&lt;/strong&gt; audio repair or upscaling, clearly unrealistic content, AI used for scripts, titles or thumbnails. A Suno bed under a human-voiced tutorial where the music is not the point also sits outside the trigger, though when unsure, tick.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Label viewers see:&lt;/strong&gt; for AI-generated music or photorealistic content the page says a label in the video player may appear. For non-music AI audio and animated content the label sits in the expanded description.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Automatic labels:&lt;/strong&gt; YouTube may add one itself for content made with its own AI tools, content carrying C2PA metadata, or content its systems detect. You get a Studio notification, and you can usually reverse a mistaken label by answering No, except for C2PA-tagged or manually reviewed content.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enforcement:&lt;/strong&gt; repeated non-disclosure may bring a manually applied label or penalties including removal or suspension from the Partner Program.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;YouTube also states that disclosing "won't limit a video's audience or impact its eligibility to earn money." So the tick costs you nothing. Skipping it is the only way it can cost you.&lt;/p&gt;

&lt;p&gt;History matters here. YouTube announced the disclosure requirement on 18 March 2024, with a description-panel label and a more prominent player label for sensitive topics such as health, news, elections and finance.&lt;a href="https://blog.youtube/news-and-events/disclosing-ai-generated-content/" rel="noopener noreferrer"&gt;[7]&lt;/a&gt; The earlier November 2023 post had already promised music partners a way to request removal of AI music that "mimics an artist's unique singing or rapping voice," limited at the time to labels and distributors.&lt;a href="https://blog.youtube/inside-youtube/our-approach-to-responsible-ai-innovation/" rel="noopener noreferrer"&gt;[8]&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Content ID: can you register a Suno track?
&lt;/h2&gt;

&lt;p&gt;Read YouTube's qualification page first. It says: "You must have exclusive rights to the material in the reference file for the territories where you claim ownership."&lt;a href="https://support.google.com/youtube/answer/2605065" rel="noopener noreferrer"&gt;[9]&lt;/a&gt; Ineligible material includes content licensed non-exclusively, Creative Commons or similar open-licence content, public domain recordings and compositions, sound-alike recordings, and sound effects, soundbeds or production loops. Content sold or licensed at scale for use in other works, with royalty-free production music as the example, goes to manual review.&lt;/p&gt;

&lt;p&gt;Notice what is not there. The page does not name AI-generated music, and it does not mention samples. So there is no written ban on Suno output. My reading is narrower and practical: exclusivity is the test, and the Suno terms give you three reasons to doubt you meet it. Output may not be unique across users, Suno disclaims any copyright vesting, and the service sells the same tool to millions. Treat a Content ID reference for a pure Suno generation as a claim you cannot defend.&lt;/p&gt;

&lt;p&gt;Distributors add their own filter. LANDR, for one, rules AI-generated tracks out of Content ID, as set out in the &lt;a href="https://dev.to/blogs/ai-music-rules-by-platform-matrix-october-2026"&gt;platform rules matrix&lt;/a&gt;, so go there for the per-distributor answer rather than assuming. If your track has your own lyrics, your own recorded vocal or played parts, the exclusive-rights argument improves, but you are then registering the human layer. Keep stems and project files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Suno song gets claimed, and how to dispute it
&lt;/h2&gt;

&lt;p&gt;A claim appears when an upload matches a reference file in Content ID, and the owner's settings then block, monetise or track the video. Claims usually do not affect your channel standing.&lt;a href="https://support.google.com/youtube/answer/6013276" rel="noopener noreferrer"&gt;[10]&lt;/a&gt; What I cannot source is the mechanism by which a Suno song specifically triggers a claim, and I will not guess at Suno's registrations. Two causes are plausible and checkable in Studio: someone registered a near-identical track as a reference, or a sample or loop inside the song came from a rights-holder. The claim detail shows which reference matched and for what timestamp. Read it before disputing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dispute steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;YouTube Studio, then Content. Filter videos by Claims and open See details under Restrictions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under Content used, choose Take action, then Dispute.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The claimant has &lt;strong&gt;30 days&lt;/strong&gt; to respond. If they do not, the claim expires and is released.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If they reinstate it, you may appeal, and the claimant then has &lt;strong&gt;7 days&lt;/strong&gt;. Some blocking claims offer Escalate to Appeal, which also gives 7 days.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two warnings from the same page. You cannot cancel a dispute once it is submitted. And a claimant can file a copyright removal request at any time; if it is valid, the video comes down and the channel gets a strike.&lt;a href="https://support.google.com/youtube/answer/2797454" rel="noopener noreferrer"&gt;[11]&lt;/a&gt; YouTube does not mediate copyright disputes, and disputing without a valid reason can lead to that removal request. Dispute only when you hold the download from a paid-plan month, or wrote the part that matched. Suno's own help article warns that monetising material you do not fully own can cost you the channel and get future releases blocked by distributors.&lt;a href="https://help.suno.com/en/articles/2410177" rel="noopener noreferrer"&gt;[3]&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One Shorts rule from the claims page: a claimed Short between one and three minutes is blocked, whatever the owner's policy says.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monetisation: the inauthentic content rule
&lt;/h2&gt;

&lt;p&gt;On 15 July 2025 YouTube renamed "repetitious content" to "inauthentic content" in its Partner Program policy, calling it a minor update that clarifies mass-produced content is covered. The substance sits under "Generic or Repetitive Content," which includes "AI-generated content made with generic or unoriginal templates" and "image slideshows, templated storylines, or scrolling text with minimal or no narrative."&lt;a href="https://support.google.com/youtube/answer/1311392" rel="noopener noreferrer"&gt;[12]&lt;/a&gt; Reusing the same intro and outro is fine if the main content differs.&lt;/p&gt;

&lt;p&gt;For Suno users the trap is the pipeline: 150 songs, one still image each, one title formula. That reads as template-made. A channel with distinct artwork, lyrics videos with real design work, commentary, or process content passes the "creative value" test far more easily. This is judgement-based, and YouTube gives no numeric threshold I could find.&lt;/p&gt;

&lt;h2&gt;
  
  
  Voice likeness and other tools
&lt;/h2&gt;

&lt;p&gt;Voice cloning is where the risk jumps. YouTube said in March 2024 it was building a privacy request process for synthetic content simulating an identifiable person's face or voice.&lt;a href="https://blog.youtube/news-and-events/disclosing-ai-generated-content/" rel="noopener noreferrer"&gt;[7]&lt;/a&gt; I could not retrieve the current official page for that process, so I am not stating its criteria or timelines. The safe rule needs no page: never publish a Suno vocal that imitates a named singer.&lt;/p&gt;

&lt;p&gt;For context, Dream Track and the Music AI tools are YouTube's own Lyria-based Shorts features. Their 2026 availability is unconfirmed here, so treat them as background, not a plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenarios and outcomes
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Disclosure tick&lt;/th&gt;
&lt;th&gt;Content ID&lt;/th&gt;
&lt;th&gt;Monetisation&lt;/th&gt;
&lt;th&gt;Risk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Hobbyist posts a free-plan song with a photo | Yes (AI music is the focus) | No | None. Free-plan songs cannot be monetised | Low if ads stay off; a monetised upload breaks Suno terms |&lt;/p&gt;

&lt;p&gt;| Monetised channel posts 40 Pro-plan songs, one template, still art | Yes, every upload | No | Eligible on paper; exposed to inauthentic content review | High. Templated AI output is the named example |&lt;/p&gt;

&lt;p&gt;| Writer records own vocal over a Suno bed, releases via distributor | Yes | Ask the distributor; register only the human layer | Pro plan covers the Suno part | Medium. Keep stems, split sheet and AI credit |&lt;/p&gt;

&lt;p&gt;Outcomes: the hobbyist is fine as long as ads are off. The monetised channel should vary visuals and structure, or accept it may lose monetisation. The distributor release lives or dies on the distributor's AI policy, covered in the &lt;a href="https://dev.to/blogs/ai-music-rules-by-platform-matrix-october-2026"&gt;matrix post&lt;/a&gt; and the &lt;a href="https://dev.to/blogs/ai-music-metadata-release-checklist-ddex-ai-credits-spam-filter-2026"&gt;metadata checklist&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Release checklist
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Confirm the track was made and downloaded during a paid month. Screenshot the download.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keep the Suno project link, your lyrics file and any stems you recorded.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write an AI credit in the description and distributor fields. Identity questions for AI-assisted artists are in the &lt;a href="https://dev.to/blogs/spotify-ai-persona-badge-identity-stack-ai-assisted-artists-2026"&gt;persona badge post&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tick the YouTube Studio AI disclosure when the music is the point.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decide Content ID before upload: default no for pure Suno output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Vary titles, art and format across a batch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Write a split sheet if anyone else wrote a lyric or played a part.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick the model deliberately; our &lt;a href="https://dev.to/blogs/suno-v6-vs-v6-wild-vs-v6-mini-which-model-for-which-song-2026"&gt;Suno v6 model comparison&lt;/a&gt; helps, and the &lt;a href="https://dev.to/tools/suno-prompt-builder"&gt;Suno Prompt Builder&lt;/a&gt; keeps your own lyrics in the song.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I monetise a Suno song on YouTube?
&lt;/h3&gt;

&lt;p&gt;Only if you made and downloaded it on a Pro or Premier plan. Suno says free-plan songs cannot be monetised. You also need to pass Partner Program rules on repetitive content.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I have to tick the AI disclosure for Suno music?
&lt;/h3&gt;

&lt;p&gt;Yes when the music is the main focus of the video. YouTube states disclosure does not limit audience or monetisation eligibility, and repeated non-disclosure can bring penalties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I put a Suno track in Content ID?
&lt;/h3&gt;

&lt;p&gt;YouTube requires exclusive rights and does not name AI music in its exclusions. Suno says output may not be unique across users, so pure Suno generations are a poor fit. Ask your distributor first.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long does a Content ID dispute take?
&lt;/h3&gt;

&lt;p&gt;The claimant has 30 days to respond to a dispute and 7 days to respond to an appeal. A rejected dispute can lead to a copyright removal request and a strike if valid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Will YouTube demonetise my channel for AI music alone?
&lt;/h3&gt;

&lt;p&gt;No policy I found does that. The risk is mass-produced, templated content under the inauthentic content rule, which applies to human-made templates too.&lt;/p&gt;

&lt;p&gt;Policies above are checked as of October 2026. Recheck the linked pages before each batch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This article is for informational purposes only and does not constitute legal advice. Platform policies change often; confirm current terms with YouTube, Suno and your distributor before release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://suno.com/terms" rel="noopener noreferrer"&gt;Suno Terms of Service (updated 10 August 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://help.suno.com/en/articles/9601601" rel="noopener noreferrer"&gt;Suno Help: rights on the free plan&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://help.suno.com/en/articles/2410177" rel="noopener noreferrer"&gt;Suno Help: distributing songs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://help.suno.com/en/articles/9601665" rel="noopener noreferrer"&gt;Suno Help: rights with a paid subscription&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://help.suno.com/en/articles/2746945" rel="noopener noreferrer"&gt;Suno Help: copyrights to songs you made&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.google.com/youtube/answer/14328491" rel="noopener noreferrer"&gt;YouTube Help: disclosing altered or synthetic content&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.youtube/news-and-events/disclosing-ai-generated-content/" rel="noopener noreferrer"&gt;YouTube Blog, 18 March 2024&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.youtube/inside-youtube/our-approach-to-responsible-ai-innovation/" rel="noopener noreferrer"&gt;YouTube Blog, 14 November 2023&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.google.com/youtube/answer/2605065" rel="noopener noreferrer"&gt;YouTube Help: Content ID qualification&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.google.com/youtube/answer/6013276" rel="noopener noreferrer"&gt;YouTube Help: Content ID claims&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.google.com/youtube/answer/2797454" rel="noopener noreferrer"&gt;YouTube Help: disputing a Content ID claim&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  12. &lt;a href="https://support.google.com/youtube/answer/1311392" rel="noopener noreferrer"&gt;YouTube Help: Partner Program policies&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/suno-songs-youtube-content-id-disclosure-monetisation-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sunoyoutube</category>
      <category>youtubeai</category>
      <category>sunocopyright</category>
      <category>youtubeinauthentic</category>
    </item>
    <item>
      <title>Suno Speech Beta Review 2026: Pricing vs ElevenLabs</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Thu, 15 Oct 2026 20:12:25 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/suno-speech-beta-review-2026-pricing-vs-elevenlabs-kni</link>
      <guid>https://dev.to/akaranjkar08/suno-speech-beta-review-2026-pricing-vs-elevenlabs-kni</guid>
      <description>&lt;p&gt;&lt;strong&gt;Suno Speech (beta) is a voice-plus-music generator, not a replacement for a narration engine: as of 16 October 2026 it turns your text into spoken audio over an original score, in one track, and Suno has published no credit cost, plan quota, language list or maximum length for it.&lt;/strong&gt; Suno announced it on 1 October 2026 after about a month of private testing and opened it to all users.&lt;a href="https://suno.com/blog/introducing-speech-beta" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; The rivals are priced per character or per credit and aim for repeatable, exact reads. Below: what Speech does and does not say publicly, the licensing position, a price table for ElevenLabs, OpenAI, Google Cloud and Fish Audio checked on 16 October, disclosure rules for YouTube and Spotify, and a decision list. Anything I could not source is named as unknown rather than guessed.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Speech launched 1 October 2026 on web, iOS and Android, open to every Suno user. Suno calls it the first audio model that generates voice and music together as one cohesive track.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not published: credit cost, plan quota, languages, maximum duration, file formats, API, commercial terms specific to Speech.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Suno itself warns of drifting accents and over-long dramatic pauses. Do not use it where exact wording or timing matters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rival API prices on 16 October: OpenAI tts-1 $15 per 1M characters, Google Chirp 3 HD $30 per 1M, Fish Audio $15 per 1M UTF-8 bytes, ElevenLabs Pro $99 per month for 600,000 credits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Speech for short, expressive pieces with a score. Use a dedicated engine for audiobooks, tutorials and ads with fixed copy.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Suno Speech is, per Suno
&lt;/h2&gt;

&lt;p&gt;The announcement, posted 1 October 2026 by Chief Product Officer Jack Brody, describes the flow in two steps: enter text, which can be an idea, a poem or your own writing, then describe the voice and the musical style you want. The output is speech over original background music.&lt;a href="https://suno.com/blog/introducing-speech-beta" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; The examples Suno gives: dramatic readings of texts, voice notes with cinematic scores, meditations, poems, pep talks and bedtime stories.&lt;/p&gt;

&lt;p&gt;Trade coverage adds that the beta is on web, iOS and Android, and that it is the first voice model built into the Suno app. Suno's older open-source Bark model from 2023 was a separate text-to-speech release.&lt;a href="https://www.aimusicpreneur.com/ai-tools-news/suno-speech-beta-spoken-word-music-one-take-launch/" rel="noopener noreferrer"&gt;[2]&lt;/a&gt; A third-party guide describes the controls in more detail: you describe age range, vocal texture, emotion, accent, pace and delivery, and separately describe the soundtrack and how far it sits behind the voice. It also reports a Simple mode and an Advanced mode with voice gender, speech style and a variation setting. I could not confirm those mode names on Suno's own page, so treat them as reported, not official.&lt;a href="https://aireiter.com/blog/suno-speech-beta-guide" rel="noopener noreferrer"&gt;[3]&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Known limits Suno admits
&lt;/h3&gt;

&lt;p&gt;The announcement says the beta may have rough edges. Brody's own example: "Occasionally, British accents can wander off to Australia and back," and dramatic pauses can be exaggerated.&lt;a href="https://suno.com/blog/introducing-speech-beta" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; Pronunciation, timing and wording are not promised to repeat between runs, which is what a narration pipeline needs most.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is not published
&lt;/h3&gt;

&lt;p&gt;Checked on 16 October 2026 against Suno's blog post and pricing page: no Speech-specific credit price, no plan quota, no free-tier allowance, no supported-language list, no maximum duration, no output format specification, no API. The announcement links to Voices, Pricing and Custom Models without describing how they relate to Speech. Suno Voices, the reusable voice profile for songs, needs a verified recording, but I found no confirmation that a saved Voice can narrate in Speech, and no statement either way on cloning inside Speech. If you need a cloned narrator today, this is not the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plans, credits and licensing
&lt;/h2&gt;

&lt;p&gt;Suno's pricing page on 16 October lists Free at $0 with 50 credits per day and no commercial rights, Pro at $8 per month with 2,500 credits per month and commercial rights, and Premier at $24 per month with 10,000 credits per month and commercial rights.&lt;a href="https://suno.com/pricing" rel="noopener noreferrer"&gt;[4]&lt;/a&gt; The page does not mention Speech. So the honest answer to "what does a Speech clip cost" is: unknown, and it is drawn from the same credit pool as songs unless Suno says otherwise. Check the cost shown on the Create screen before a large batch, as the cost may differ from a song generation.&lt;/p&gt;

&lt;p&gt;Licensing is where I would be careful. The announcement states no separate commercial terms for Speech. Suno's terms of service, updated 10 August 2026, assign output you downloaded while subscribed and limit free-plan use to lawful personal, non-commercial purposes.&lt;a href="https://suno.com/terms" rel="noopener noreferrer"&gt;[5]&lt;/a&gt; My working rule, which is an inference and not a Suno statement: treat Speech output under the same plan rules as songs. Free-plan clips stay off monetised channels and client work. Paid-plan clips downloaded during a paid month are the only ones I would put in a commercial project. The full rulebook for ownership by plan sits in the &lt;a href="https://dev.to/blogs/suno-songs-youtube-content-id-disclosure-monetisation-2026"&gt;Suno on YouTube post&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it compares: prices checked 16 October 2026
&lt;/h2&gt;

&lt;p&gt;Every figure below was read from the vendor's own pricing page on 16 October 2026. Prices move, so recheck before you commit a budget.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Pricing model and figures&lt;/th&gt;
&lt;th&gt;Commercial use&lt;/th&gt;
&lt;th&gt;Strength&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Suno Speech (beta) | Plan credits (Pro $8, Premier $24 per month); Speech credit cost not published | Paid plans yes for songs; Speech-specific terms not published | Voice and score in one track |&lt;/p&gt;

&lt;p&gt;| ElevenLabs | Free 10,000 credits per month (about 10 minutes); Pro $99 per month, 600,000 credits (about 600 minutes); extra minute about $0.17 on Pro. 1 credit per character on V2 Multilingual | Yes on paid plans; not listed on Free | Voice quality, cloning, control |&lt;/p&gt;

&lt;p&gt;| OpenAI TTS | tts-1 $15 per 1M characters; tts-1-hd $30 per 1M characters; gpt-4o-mini-tts $0.60 per 1M text tokens in plus $12 per 1M audio tokens out | API output usable per OpenAI terms | Cheap, simple API |&lt;/p&gt;

&lt;p&gt;| Google Cloud TTS | Per 1M characters: Standard and WaveNet $4, Neural2 $16, Chirp 3 HD $30, Studio $160. Free monthly tier: 4M characters Standard and WaveNet, 1M for the others | API output usable per Google Cloud terms | Scale, languages, free tier |&lt;/p&gt;

&lt;p&gt;| Fish Audio | API $15 per 1M UTF-8 bytes, pay as you go (about 12 hours of speech per 1M bytes, per Fish docs). Plus plan $5.50 per month billed annually (promo), 250,000 credits | Plus, Pro, Max yes; Free is personal use only | Low cost, voice cloning |&lt;/p&gt;

&lt;p&gt;Sources: &lt;a href="https://elevenlabs.io/pricing" rel="noopener noreferrer"&gt;ElevenLabs&lt;/a&gt;, &lt;a href="https://developers.openai.com/api/docs/pricing" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt;, &lt;a href="https://cloud.google.com/text-to-speech/pricing" rel="noopener noreferrer"&gt;Google Cloud&lt;/a&gt;, &lt;a href="https://docs.fish.audio/developer-guide/models-pricing/pricing-and-rate-limits" rel="noopener noreferrer"&gt;Fish Audio API docs&lt;/a&gt; and the &lt;a href="https://fish.audio/plan/" rel="noopener noreferrer"&gt;Fish Audio plans page&lt;/a&gt;. Fish Audio's pricing page contradicts itself on Free-plan commercial use (the table lists it, the FAQ says personal only), so assume personal only.&lt;/p&gt;

&lt;h3&gt;
  
  
  What a ten-minute narration costs
&lt;/h3&gt;

&lt;p&gt;A ten-minute read is roughly 1,500 words, or about 9,000 characters at six characters a word. That is my arithmetic from the table, not a vendor figure. On those assumptions OpenAI tts-1 costs about $0.14, tts-1-hd about $0.27, Google Chirp 3 HD about $0.27, Google Studio about $1.44 and Google Standard about $0.04. Fish Audio at its documented rate of about 12 hours per $15 comes to around $0.21 for ten minutes. ElevenLabs on Pro works out near $1.70 at the listed extra-minute rate. Suno Speech cannot be priced until Suno publishes the credit cost. The spread is the point: for plain narration, API engines cost cents, so Speech earns its place only when you want the score.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality and latency: what I can and cannot say
&lt;/h2&gt;

&lt;p&gt;I have no benchmark to cite, and I will not invent one. What the sources support: Suno's own warnings about accents and pauses; a third-party guide that rates Speech poorly for audiobook chapters and timecoded tutorials and says it suits short, expressive pieces; and one Reddit user calling the demo "worryingly bad", which that guide treats as anecdote.&lt;a href="https://aireiter.com/blog/suno-speech-beta-guide" rel="noopener noreferrer"&gt;[3]&lt;/a&gt; If you need clean voice with no music, the guide reports a community workaround (turn the background music off, set variety fully left, add "No background music." to the tone instruction) and says music still appeared in one test. Suno does not guarantee isolated voice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disclosure when you publish synthetic voices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  YouTube
&lt;/h3&gt;

&lt;p&gt;YouTube's altered or synthetic content rules cover realistic content, and its help page names AI-generated music as an example when the music is the main focus of the video. A Speech clip with a score is a hybrid, so if the clip is the thing viewers came for, tick the disclosure. Disclosing does not limit audience or monetisation eligibility, per YouTube. The sourced detail, including labels and enforcement, is in the &lt;a href="https://dev.to/blogs/suno-songs-youtube-content-id-disclosure-monetisation-2026"&gt;YouTube disclosure post&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spotify podcasts
&lt;/h3&gt;

&lt;p&gt;I found no Spotify rule that makes AI-voice disclosure mandatory for podcast episodes. What exists is an impersonation ban: in a post dated 19 May 2026 Spotify reaffirmed that it removes shows copying another creator's likeness, including through voice cloning, without permission.&lt;a href="https://newsroom.spotify.com/2026-05-19/podcast-verification-trust-creators-listeners/" rel="noopener noreferrer"&gt;[6]&lt;/a&gt; Spotify's AI credits feature is for music, is in beta and is optional.&lt;a href="https://support.spotify.com/gw-en/artists/article/ai-credits/" rel="noopener noreferrer"&gt;[7]&lt;/a&gt; Whether a Speech-made episode intro needs a label is therefore unconfirmed. A one-line mention in the show notes costs nothing. For the music side across services see the &lt;a href="https://dev.to/blogs/ai-music-rules-by-platform-matrix-october-2026"&gt;AI music rules matrix&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it fits in a Suno workflow
&lt;/h2&gt;

&lt;p&gt;Speech sits next to songs, not instead of a voice engine. Three placements that match what Suno describes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Song intros and outros.&lt;/strong&gt; A 20-second spoken lead-in with a matching score, generated with the same mood words you use in the song prompt. Keep the style tags aligned using the &lt;a href="https://dev.to/tools/suno-prompt-builder"&gt;Suno Prompt Builder&lt;/a&gt;, and pick the song model with the &lt;a href="https://dev.to/blogs/suno-v6-vs-v6-wild-vs-v6-mini-which-model-for-which-song-2026"&gt;v6 model comparison&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Short-form clips.&lt;/strong&gt; Pep talks, poems, scored voice notes for Shorts and Reels, where a slightly odd read is a feature.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The guide's prompting advice is worth following: paste the finished script, because giving the exact text gives more control than asking Suno to write it; use short sentences and paragraph breaks; drop end rhymes and refrains, which push the delivery toward singing; and generate several takes instead of stacking corrections.&lt;a href="https://aireiter.com/blog/suno-speech-beta-guide" rel="noopener noreferrer"&gt;[3]&lt;/a&gt; Regional-language song makers building voice-led intros can pair this with the &lt;a href="https://dev.to/product/regional-indian-music-pack-suno"&gt;Regional Indian Music Pack for Suno&lt;/a&gt;, though language support in Speech itself is unpublished, so test your language before planning around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use which
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Audiobook chapters, e-learning, timecoded tutorials:&lt;/strong&gt; a dedicated engine. Google Chirp 3 HD or OpenAI tts-1-hd for cost; ElevenLabs when voice quality is the product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Podcast narration with a fixed script:&lt;/strong&gt; ElevenLabs or Fish Audio, where you can re-run a line and get the same wording.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ads with legal copy or product names:&lt;/strong&gt; never Speech in beta. Pronunciation and wording are not guaranteed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloned brand voice:&lt;/strong&gt; ElevenLabs or Fish Audio on a paid commercial plan, with consent on file. Speech has no confirmed cloning.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bulk, low-cost, many languages:&lt;/strong&gt; Google Cloud, which has the free tier.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Atmospheric clip where voice and score must feel like one piece:&lt;/strong&gt; Suno Speech, on a paid plan if the clip goes anywhere commercial.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is Suno Speech?
&lt;/h3&gt;

&lt;p&gt;A beta mode, released 1 October 2026, that generates spoken audio and original background music together as a single track from your text and a description of the voice and style. It is open to all users on web, iOS and Android.&lt;/p&gt;

&lt;h3&gt;
  
  
  How much does Suno Speech cost?
&lt;/h3&gt;

&lt;p&gt;Suno has not published a Speech-specific credit cost or plan quota as of 16 October 2026. Suno's plans are Free (50 credits a day), Pro $8 and Premier $24 a month. Check the Create screen for the cost before batching.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Suno Speech clips commercially?
&lt;/h3&gt;

&lt;p&gt;Suno published no separate Speech terms. Its terms of service, updated 10 August 2026, limit free-plan use to personal, non-commercial purposes. Treat paid-plan downloads as the only commercial candidates, and confirm with Suno if the project matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Suno Speech better than ElevenLabs?
&lt;/h3&gt;

&lt;p&gt;Different job. ElevenLabs is built for repeatable narration and cloning. Speech is built for expressive voice with a score, and Suno warns of accent drift and long pauses. I have no sourced head-to-head quality test, so I will not rank them on quality.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Suno Speech support voice cloning or other languages?
&lt;/h3&gt;

&lt;p&gt;Neither is confirmed. Suno's announcement lists no languages and does not say whether Voices can narrate in Speech. Test your language and assume no cloning until Suno documents it.&lt;/p&gt;

&lt;p&gt;All facts above are dated 16 October 2026. The beta is moving, so recheck the &lt;a href="https://suno.com/blog/introducing-speech-beta" rel="noopener noreferrer"&gt;announcement&lt;/a&gt; and the pricing pages before you build a workflow on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://suno.com/blog/introducing-speech-beta" rel="noopener noreferrer"&gt;Suno blog: Introducing Speech (beta), 1 October 2026&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.aimusicpreneur.com/ai-tools-news/suno-speech-beta-spoken-word-music-one-take-launch/" rel="noopener noreferrer"&gt;AI Musicpreneur: Suno Speech beta launch coverage&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://aireiter.com/blog/suno-speech-beta-guide" rel="noopener noreferrer"&gt;Aireiter: Suno Speech beta guide (third party)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://suno.com/pricing" rel="noopener noreferrer"&gt;Suno pricing&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://suno.com/terms" rel="noopener noreferrer"&gt;Suno Terms of Service (updated 10 August 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://newsroom.spotify.com/2026-05-19/podcast-verification-trust-creators-listeners/" rel="noopener noreferrer"&gt;Spotify Newsroom, 19 May 2026&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  7. &lt;a href="https://support.spotify.com/gw-en/artists/article/ai-credits/" rel="noopener noreferrer"&gt;Spotify Support: AI credits&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/suno-speech-beta-review-pricing-vs-elevenlabs-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>sunospeech</category>
      <category>sunovs</category>
      <category>sunotext</category>
      <category>aivoice</category>
    </item>
    <item>
      <title>Section 393 TDS Map: Old 194C, 194J to New Rows (2026)</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Thu, 15 Oct 2026 19:27:35 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/section-393-tds-map-old-194c-194j-to-new-rows-2026-geg</link>
      <guid>https://dev.to/akaranjkar08/section-393-tds-map-old-194c-194j-to-new-rows-2026-geg</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; From 1 April 2026, old sections 193 to 196D collapse into section 393 of the Income-tax Act 2025, and salary TDS (old 192) moves to section 392. Rates and thresholds did not change; the Finance Act 2026 adjusted a few exemptions and the declaration procedure. What changed is the label: for any payment or credit on or after 1 April 2026 you quote the s.393 table row, for example 393(1) Sl. No. 6(i) for contractors, and not 194C. Returns move to Forms 138, 140, 144 and 143, certificates to Forms 130 and 131, deposit stays at the 7th of the next month. This post carries the old-to-new map, the dates, and a November 2026 worked example.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Section 393 is a set of tables, not a list of sections, and every non-salary TDS payment made since 1 April 2026 maps to a row in it.&lt;/strong&gt; The CBDT's own transition FAQs say all of old sections 192 to 194T are "consolidated under two sections, section 392 and section 393"[1]. Rates and thresholds are "largely the same"[1], and a later answer drops the hedge: no change in rates or monetary thresholds for any category[1]. The risk is clerical. Quote 194C on a May payment and the return can fail validation. Below: how the section is built, the full map with a confidence mark on every row, the rows where sources disagree, the form changes, a dates table, and a Nov 2026 example for a small company.&lt;/p&gt;

&lt;p&gt;For the amount on one payment, use the &lt;a href="https://dev.to/tools/tds-calculator"&gt;TDS calculator&lt;/a&gt;; this post tells you which row to quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  How section 393 is built
&lt;/h2&gt;

&lt;p&gt;The department describes s.393 as "3 Tables applicable to three broad categories of Payees": residents, non-residents and any person. Each table lists the nature of income, the payer, the threshold and the rate[1]. The Act text, as amended by the Finance Act 2026, adds the rest[2]:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;393(1):&lt;/strong&gt; payments to residents, eight serial numbers with lettered sub-rows. Deduction is on the entire amount once the threshold is crossed, at the earlier of credit or payment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;393(2):&lt;/strong&gt; payments to non-residents, 17 serial numbers, no thresholds.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;393(3):&lt;/strong&gt; payments to any person, 7 serial numbers (winnings, cash withdrawals, partner payments).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;393(4):&lt;/strong&gt; a table of 19 no-deduction cases lifted from the old provisos.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;393(5):&lt;/strong&gt; payees who never suffer TDS (old 196).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;393(6):&lt;/strong&gt; the nil-tax declaration, old 197A, now Form 121.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"Sl. No. 6(i)" means table row 6, clause (i); the CBDT's own quoting form is "Section 393(1) [Table: Sl. No. 6(i)]"[1]. TCS is not here; it moved to section 394[1].&lt;/p&gt;

&lt;h2&gt;
  
  
  Did rates or thresholds change?
&lt;/h2&gt;

&lt;p&gt;No, with one nuance on timing. The CBDT FAQ says thresholds and rates were retained "as they are under the Income-tax Act, 1961" and that the consolidation is "a simplified tabular presentation and not a change in TDS rates or tax policy"[1]. What carried over is the 1961 Act as it stood after Finance Act 2025, which had already lifted several limits from 1 April 2025. The Act text shows the carried-over figures[2]:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Payment&lt;/th&gt;
&lt;th&gt;Threshold now&lt;/th&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Commission or brokerage (old 194H) | ₹20,000 a year | 393(1) Sl. 1(ii) |&lt;/p&gt;

&lt;p&gt;| Rent (old 194-I, 194-IB) | ₹50,000 for a month or part of a month | 393(1) Sl. 2 |&lt;/p&gt;

&lt;p&gt;| Professional or technical fees (old 194J) | ₹50,000 a year; nil for director fees | 393(1) Sl. 6(iii) |&lt;/p&gt;

&lt;p&gt;| Bank interest (old 194A) | ₹50,000; ₹1,00,000 for senior citizens | 393(1) Sl. 5(ii) |&lt;/p&gt;

&lt;p&gt;| Contractors (old 194C) | ₹30,000 a payment or ₹1,00,000 a year | 393(1) Sl. 6(i) |&lt;/p&gt;

&lt;p&gt;| Mutual fund units (old 194K) | ₹10,000 | 393(1) Sl. 4(i) |&lt;/p&gt;

&lt;p&gt;| Partner payments by a firm (old 194T) | ₹20,000 | 393(3) Sl. 7 |&lt;/p&gt;

&lt;p&gt;The rent row deserves a flag. Many posts say the rent limit is ₹6,00,000 a year. The statutory words, in both the old s.194-I text and the new row, test the rent for "a month or part of a month" against ₹50,000[2]. A tenant paying ₹49,000 a month crosses ₹5.88 lakh and owes nothing. One month at ₹52,000 can trigger it. Test monthly.&lt;/p&gt;

&lt;p&gt;The Finance Act 2026 (Act No. 4 of 2026) amended section 393 in five places[2]. (1) Note 3 to the Table in sub-section (1) now ties the ₹50 lakh test to row 3(i) instead of 3(iii). (2) Co-operative banks, including co-operative land mortgage banks, join the interest no-deduction list in sub-section (4), row 7(a)(i). (3) Interest on Motor Accidents Claims Tribunal compensation is exempt without a cap for an individual and capped at ₹50,000 a year for anyone else, row 7(c)(iv). (4) Declarations under sub-section (7) are forwarded quarterly, by the 7th of the month after each quarter, instead of monthly. (5) From 1 April 2027, sub-section (6)(b) lets declarations go electronically to a depository.&lt;/p&gt;

&lt;h2&gt;
  
  
  The old-to-new map
&lt;/h2&gt;

&lt;p&gt;Every row below was checked against the Act text as amended by the Finance Act 2026[2], and the CBDT FAQ[1] where it speaks to the row. The Act prints no old section numbers, so the old-to-new link is by content. "Specified person" is anyone other than an individual or HUF, plus an individual or HUF above ₹1 crore business turnover or ₹50 lakh professional receipts in the preceding year[2].&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Old section&lt;/th&gt;
&lt;th&gt;New location&lt;/th&gt;
&lt;th&gt;Nature of payment&lt;/th&gt;
&lt;th&gt;Threshold&lt;/th&gt;
&lt;th&gt;Rate&lt;/th&gt;
&lt;th&gt;Payer&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| 192 | s.392(1) | Salary | Slab based | Slab rates | Employer | P |&lt;/p&gt;

&lt;p&gt;| 193 | 393(1) Sl. 5(i) | Interest on securities | ₹10,000 | Rates in force (10%) | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194 | 393(1) Sl. 7 | Dividend | Nil; see 393(4) | 10% | Domestic company | P |&lt;/p&gt;

&lt;p&gt;| 194A | 393(1) Sl. 5(ii) | Interest from bank, co-op bank, post office | ₹50,000 / ₹1,00,000 senior | Rates in force (10%) | Bank, co-op bank, post office | P |&lt;/p&gt;

&lt;p&gt;| 194A | 393(1) Sl. 5(iii) | Other interest | ₹10,000 | Rates in force (10%) | Specified person | P |&lt;/p&gt;

&lt;p&gt;| 194B | 393(3) Sl. 1 | Lottery, puzzle, card game winnings | ₹10,000 a transaction | 30% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194BA | 393(3) Sl. 2 | Net online game winnings | None | 30% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194BB | 393(3) Sl. 3 | Horse race winnings | ₹10,000 a transaction | 30% | Bookmaker or race course | P |&lt;/p&gt;

&lt;p&gt;| 194C | 393(1) Sl. 6(i) | Contractor, including labour supply | ₹30,000 a payment or ₹1,00,000 a year | 1% individual or HUF; 2% others | Designated person | P |&lt;/p&gt;

&lt;p&gt;| 194D | 393(1) Sl. 1(i) | Insurance commission | ₹20,000 | Rates in force (2%; 10% for a domestic company payee) | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194DA | 393(1) Sl. 8(i) | Life insurance payout (taxable part) | ₹1,00,000 | 2% of income part | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194EE | 393(3) Sl. 6 | NSS withdrawals | ₹2,500 | 10% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194G | 393(3) Sl. 4 | Lottery ticket commission | ₹20,000 | 2% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194H | 393(1) Sl. 1(ii) | Commission or brokerage | ₹20,000 | 2% | Specified person | P |&lt;/p&gt;

&lt;p&gt;| 194-I | 393(1) Sl. 2(ii) | Rent | ₹50,000 a month | 2% plant and machinery; 10% land, building, furniture | Specified person | P |&lt;/p&gt;

&lt;p&gt;| 194-IA | 393(1) Sl. 3(i) | Immovable property transfer | ₹50 lakh | 1% of higher of price or stamp value | Transferee | P |&lt;/p&gt;

&lt;p&gt;| 194-IB | 393(1) Sl. 2(i) | Rent by non-specified person | ₹50,000 a month | 2%, once, for the last month | Individual or HUF not specified | P |&lt;/p&gt;

&lt;p&gt;| 194-IC | 393(1) Sl. 3(ii) | Joint development agreement | Nil | 10% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194J | 393(1) Sl. 6(iii) | Professional and technical fees, director fees, royalty | ₹50,000; nil for director fees | 2% technical, film royalty, call centre; 10% others | Specified person | P |&lt;/p&gt;

&lt;p&gt;| 194K | 393(1) Sl. 4(i) | Mutual fund units | ₹10,000 | 10% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194LA | 393(1) Sl. 3(iii) | Compulsory acquisition compensation | ₹5,00,000 | 10% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194LBA, LBB, LBC (resident) | 393(1) Sl. 4(ii) to (iv) | Business trust, investment fund, securitisation trust | Nil | 10% | The trust or fund | P |&lt;/p&gt;

&lt;p&gt;| 194M | 393(1) Sl. 6(ii) | Contract, professional fees, commission by individual or HUF | ₹50 lakh | 2% | Individual or HUF not covered elsewhere | P |&lt;/p&gt;

&lt;p&gt;| 194N | 393(3) Sl. 5 | Cash withdrawals | ₹1 crore; ₹3 crore for co-op societies | 2% | Bank, co-op bank, post office | P |&lt;/p&gt;

&lt;p&gt;| 194-O | 393(1) Sl. 8(v) | E-commerce participant payments | Nil; ₹5 lakh exemption in 393(4) | 0.1% | E-commerce operator | P |&lt;/p&gt;

&lt;p&gt;| 194P | 393(1) Sl. 8(iii) | Specified senior citizen (75+) | As applicable | Rates in force | Specified bank | P |&lt;/p&gt;

&lt;p&gt;| 194Q | 393(1) Sl. 8(ii) | Purchase of goods | Above ₹50 lakh, on the excess | 0.1% | Buyer, as defined in s.402(6): turnover above ₹10 crore in the preceding tax year | P |&lt;/p&gt;

&lt;p&gt;| 194R | 393(1) Sl. 8(iv) | Business benefit or perquisite | ₹20,000 | 10% of value | Specified person | P |&lt;/p&gt;

&lt;p&gt;| 194S | 393(1) Sl. 8(vi) | Virtual digital asset transfer | Nil; small-payer limits in 393(4) | 1% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194T | 393(3) Sl. 7 | Partner salary, bonus, interest | ₹20,000 | 10% | Firm | P |&lt;/p&gt;

&lt;p&gt;| 195 | 393(2) Sl. 17 | Other sums to non-residents | None | Rates in force or treaty rate | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194E | 393(2) Sl. 1 | Non-resident sportsmen, entertainers, sports bodies | None | 20% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 194LC | 393(2) Sl. 2 to 4 | Interest on specified foreign currency and rupee bonds | None | 5%; 4% or 9% for IFSC-listed bonds | Indian company or business trust | P |&lt;/p&gt;

&lt;p&gt;| 194LB | 393(2) Sl. 5 | Infrastructure debt fund interest | None | 5% | Infrastructure debt fund | P |&lt;/p&gt;

&lt;p&gt;| 194LBA (non-resident) | 393(2) Sl. 6 to 7 | Business trust distributions | None | 5% / 10%; rates in force | Business trust | P |&lt;/p&gt;

&lt;p&gt;| 194LBB, 194LBC (non-resident) | 393(2) Sl. 8 and 9 | Investment fund and securitisation trust income | None | Rates in force | The fund or trust | P |&lt;/p&gt;

&lt;p&gt;| 196A | 393(2) Sl. 10 | Mutual fund units | None | 20% or treaty rate | Any person | P |&lt;/p&gt;

&lt;p&gt;| 196B, 196C | 393(2) Sl. 11 to 14 | Offshore fund units; bonds and GDRs | None | 10% / 12.5% | Any person | P |&lt;/p&gt;

&lt;p&gt;| 196D | 393(2) Sl. 15 and 16 | FII and specified fund securities income | None | 20% or treaty rate; 10% | Any person | P |&lt;/p&gt;

&lt;p&gt;All 32 rows checked against the Act text as amended by the Finance Act 2026. The non-resident rows are matched by content, because the Act prints no old section numbers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Related provisions that moved with it
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;1961 Act&lt;/th&gt;
&lt;th&gt;2025 Act&lt;/th&gt;
&lt;th&gt;Subject&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| 197 | s.395(1) | Lower or nil deduction certificate | P[1] |&lt;/p&gt;

&lt;p&gt;| 197A, Forms 15G/15H | s.393(6), Form 121 | Nil-tax declaration | P[1] |&lt;/p&gt;

&lt;p&gt;| 195(6), Forms 15CA/15CB | s.397(3)(d), Forms 145/146 | Foreign remittance information | P[1] |&lt;/p&gt;

&lt;p&gt;| 201(1A) | s.398(3)(a) | Interest: 1% a month for non-deduction, 1.5% for late deposit | P[1] |&lt;/p&gt;

&lt;p&gt;| 40(a)(ia) | s.35(b) | 30% disallowance for non-deduction or late deposit | P[1] |&lt;/p&gt;

&lt;p&gt;| 234E | s.427 | Late fee on TDS statements, ₹200 a day | P[2] |&lt;/p&gt;

&lt;p&gt;| 206C (TCS) | s.394 | Tax collected at source | P[1] |&lt;/p&gt;

&lt;h2&gt;
  
  
  Where published mappings disagree
&lt;/h2&gt;

&lt;p&gt;The department runs a section-comparison utility on its Act 2025 page[5]. It is a script-driven tool, so I could not export its rows and cannot tell you which of them differ from the Act. What I can show is where commercial mapping tables disagree with the Act text or the CBDT FAQ. These are the ones to watch.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Contractors.&lt;/strong&gt; One mapping puts 194C at "Serial 8". The CBDT FAQ gives 393(1) [Table: Sl. No. 6(i)] twice, in its quoting example and its monthly-contract example[1]. Use 6(i). The likely origin of the wrong number is sub-section (4) row 8, the no-deduction row for small transporters under 6(i).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Professional fees.&lt;/strong&gt; Some sites write the row as "6(iii).D(a)" and "6(iii).D(b)" for the 2% and 10% rates[4]. In the Act text 6(iii) is one row with the two rates in column D[2]. Quote 6(iii) and pick the rate by the nature of the service. Reporting a professional fee at the 2% technical rate is the error to avoid.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Professional fee threshold.&lt;/strong&gt; One payment-code reference lists ₹30,000 for professional and technical fees. The Act text says ₹50,000[2].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Number of tables.&lt;/strong&gt; Section 393 has five: the three payee tables, the sub-section (4) no-deduction table and the sub-section (6) declaration table[2]. The CBDT counts the three payee tables[1]. A TaxGuru explainer says six[3], which the Act does not support.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Rent.&lt;/strong&gt; The ₹6 lakh a year versus ₹50,000 a month point above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Purchase of goods.&lt;/strong&gt; The row's payer column reads only "buyer". The ₹10 crore test sits in the definition of "buyer" in s.402(6): turnover above ₹10 crore in the preceding tax year[2]. Commercial tables that state it in the payer column are right on substance.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Forms and certificates
&lt;/h2&gt;

&lt;p&gt;The CBDT FAQ lists the replacements for the deductor-side forms[1]:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;1961 Act&lt;/th&gt;
&lt;th&gt;2025 Act&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Salary TDS return | 24Q | Form 138 |&lt;/p&gt;

&lt;p&gt;| Non-salary TDS return | 26Q | Form 140 |&lt;/p&gt;

&lt;p&gt;| Non-resident TDS return | 27Q | Form 144 |&lt;/p&gt;

&lt;p&gt;| TCS return | 27EQ | Form 143 |&lt;/p&gt;

&lt;p&gt;| Challan-cum-statement | 26QB, 26QC, 26QD, 26QE | Form 141, one form for all four cases |&lt;/p&gt;

&lt;p&gt;| Salary TDS certificate | Form 16 | Form 130 |&lt;/p&gt;

&lt;p&gt;| Non-salary TDS certificate | Form 16A | Form 131 |&lt;/p&gt;

&lt;p&gt;| Lower deduction application | Form 13 | Form 128 |&lt;/p&gt;

&lt;p&gt;| Nil-tax declaration | 15G, 15H | Form 121 |&lt;/p&gt;

&lt;p&gt;| Annual statement for taxpayers | AIS | Form 168 from tax year 2026-27 |&lt;/p&gt;

&lt;p&gt;Form 123 replaces Form 12BA for perquisites, as covered in the &lt;a href="https://dev.to/blogs/diwali-gifts-tax-gst-tds-rules-india-2026"&gt;Diwali gifts post&lt;/a&gt;. TAN stays: the FAQ says the Tax Deduction Account Number, faceless assessment and similar frameworks "shall continue" under the new Act[1]. New TAN applications use Form 134 (government) or 135 (others).&lt;/p&gt;

&lt;h3&gt;
  
  
  Tax year, financial year, assessment year
&lt;/h3&gt;

&lt;p&gt;A "tax year" is "a period of twelve months contained in a financial year" and replaces the "previous year"[1]. There is no assessment year for income from 1 April 2026. On the portal, challans for FY 2025-26 liabilities still use AY 2026-27 and challans for FY 2026-27 use Tax Year 2026-27, and the FAQ warns that a wrong pick sends the credit to the wrong year[1].&lt;/p&gt;

&lt;h2&gt;
  
  
  Dates that matter
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Basis&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Deposit of TDS deducted in a month (non-government payer) | 7th of the next month | Rule 218, Income-tax Rules 2026[6] |&lt;/p&gt;

&lt;p&gt;| Deposit for March deduction | 30 April | Same rule, same timeline as old Rule 30[1] |&lt;/p&gt;

&lt;p&gt;| Challan-cum-statement cases (property, rent by individuals, 6(ii) payments, VDA) | 30 days from end of the month of deduction. Rule 218(3) adds a fifth case: property bought by a resident individual or HUF from a non-resident, 393(2) Sl. 17 | CBDT FAQ[1], Rule 218[6] |&lt;/p&gt;

&lt;p&gt;| Form 140/138/144/143 for Jul to Sep 2026 | 31 October 2026 | CBDT FAQ[1] |&lt;/p&gt;

&lt;p&gt;| Form 131 for Jul to Sep 2026 | 15 days after the return due date, so 15 November 2026 (a Sunday) | Derived from FAQ pattern[1] |&lt;/p&gt;

&lt;p&gt;| Form 140 for Oct to Dec 2026 | 31 January 2027 (a Sunday) | Rule 219 table: 31 Jul, 31 Oct, 31 Jan, 31 May[7] |&lt;/p&gt;

&lt;p&gt;| Form 130 for tax year 2026-27 salary | 15 June 2027 | CBDT FAQ[1] |&lt;/p&gt;

&lt;p&gt;| Interest, non-deduction / late deposit | 1% / 1.5% per month or part month | s.398(3)(a)[1] |&lt;/p&gt;

&lt;h2&gt;
  
  
  Transition checklist for October 2026 to March 2027
&lt;/h2&gt;

&lt;p&gt;The CBDT test is the earlier of credit or payment. Earlier on or before 31 March 2026 means the 1961 Act; on or after 1 April 2026 means s.393[1]. Everything in your current six-month window is under the new Act. A working list:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Payroll and ERP masters.&lt;/strong&gt; The FAQ states systems "are required to be updated" to the new numbering[1]. Replace 194x labels in vendor masters with the row from the map above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Challans.&lt;/strong&gt; Select Tax Year 2026-27. Old-Act challans stay only for deductions on payments made up to 31 March 2026[1].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Returns.&lt;/strong&gt; Q3 of the tax year goes in the new Form 140 and its siblings. Quoting 194C after 1 April "may result in system-level validation errors" and a correction statement[1].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Corrections for FY 2025-26 and earlier&lt;/strong&gt; still use the old forms[1].&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lower-deduction certificates.&lt;/strong&gt; A s.197 certificate stays valid for 2026-27 payments if it covers projected receipts for tax year 2026-27[1]. New applications use Form 128.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Vendor declarations.&lt;/strong&gt; Collect Form 121; forwarding is quarterly, not monthly[2].&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Worked example: a small company in November 2026
&lt;/h2&gt;

&lt;p&gt;A private limited company (a specified person) pays three bills in November 2026, all to resident payees with PAN, GST shown separately and excluded here.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Payment&lt;/th&gt;
&lt;th&gt;Amount&lt;/th&gt;
&lt;th&gt;Row to quote&lt;/th&gt;
&lt;th&gt;Rate&lt;/th&gt;
&lt;th&gt;TDS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Monthly office rent to an individual landlord (building) | ₹80,000 | 393(1) Sl. 2(ii) | 10% | ₹8,000 |&lt;/p&gt;

&lt;p&gt;| Chartered accountant's fee, first invoice of the year | ₹1,20,000 | 393(1) Sl. 6(iii) | 10% | ₹12,000 |&lt;/p&gt;

&lt;p&gt;| Interior fit-out contractor, a company | ₹2,50,000 | 393(1) Sl. 6(i) | 2% | ₹5,000 |&lt;/p&gt;

&lt;p&gt;| &lt;strong&gt;Total&lt;/strong&gt; |  |  |  | &lt;strong&gt;₹25,000&lt;/strong&gt; |&lt;/p&gt;

&lt;p&gt;Rent clears the monthly ₹50,000 test, so the 10% applies from the first rupee. The CA fee exceeds ₹50,000, so tax runs on the whole ₹1,20,000. The contractor payment exceeds both ₹30,000 a payment and ₹1,00,000 a year; if the contractor were a sole proprietor the rate drops to 1% and the TDS to ₹2,500.&lt;/p&gt;

&lt;p&gt;Deposit ₹25,000 by &lt;strong&gt;Monday, 7 December 2026&lt;/strong&gt;, using a Tax Year 2026-27 challan. Report all three in Form 140 for October to December 2026 under the rows above. Miss the deposit and interest runs at 1.5% a month from the date of deduction; skip the deduction and the 30% disallowance in s.35(b) applies to the expense, which on the three bills is ₹1.35 lakh of disallowed cost (30% of ₹4.5 lakh)[1]. For a figure on a different amount, run the &lt;a href="https://dev.to/tools/tds-calculator"&gt;TDS calculator&lt;/a&gt;, and for the payee's side see the &lt;a href="https://dev.to/tools/income-tax-calculator"&gt;income tax calculator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Do I quote 194C or 393 on a payment made in April 2026 for March work?
&lt;/h3&gt;

&lt;p&gt;It depends on the earlier of credit or payment. If you credited the bill in March 2026, the 1961 Act governs and 194C is correct. If both credit and payment fell on or after 1 April, quote 393(1) Sl. 6(i)[1]. The CBDT's housekeeping-contract example splits the same contract at that date.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Form 26Q gone?
&lt;/h3&gt;

&lt;p&gt;For periods from April 2026, yes: the non-salary return is Form 140[1]. Form 26Q remains the form for FY 2025-26 and earlier periods, including corrections filed later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Did the TDS deposit date change?
&lt;/h3&gt;

&lt;p&gt;No. It is still the 7th of the following month, with 30 April for March, now set by Rule 218 of the Income-tax Rules 2026[1]. Interest remains 1% and 1.5% a month under s.398(3)(a).&lt;/p&gt;

&lt;h3&gt;
  
  
  Does my old Section 197 lower-deduction certificate still work?
&lt;/h3&gt;

&lt;p&gt;Yes, if it was issued for projected receipts of tax year 2026-27[1]. A certificate valid only up to 31 March 2026 covers payments made on or before that date. Apply fresh in Form 128 under s.395(1).&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the department's mapping utility enough to rely on?
&lt;/h3&gt;

&lt;p&gt;Treat it as a finder, not the authority. The utility states "for reference purposes only" and tells users to verify against official sources[5]. The Act text and the CBDT FAQ are what you cite. Where you see a serial that differs, such as 194C at "Serial 8", go to the Table.&lt;/p&gt;

&lt;h3&gt;
  
  
  What if I already deducted under the wrong section?
&lt;/h3&gt;

&lt;p&gt;The deduction stands if rate and amount were right. The FAQ says wrong section references may need a correction statement[1], and a mismatch in the payee's credit is fixed by a revised return from the deductor[1]. Correct them before certificates go out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/documents/20117/43120/Updated-FQAs-on-Interplay%26Transitions.pdf/dda21cfd-28be-d931-ad5c-6459ecbd2ea7?version=2.0&amp;amp;t=1791877981764" rel="noopener noreferrer"&gt;CBDT / Income Tax Department, FAQs on Interplay and Transition from the Income Tax Act, 1961 to the Income Tax Act, 2025, version 2.0 (primary; read in full via a text mirror because the PDF host blocked direct fetch; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/documents/d/guest/income_tax_act_2025_as_amended_by_fa_act_2026-pdf" rel="noopener noreferrer"&gt;Income Tax Department, Income-tax Act 2025 as amended by the Finance Act 2026 (primary; 686 pages; the host blocks direct fetch but serves through a text mirror; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://taxguru.in/income-tax/section-393-income-tax-act-2025-tax-deduction-source.html" rel="noopener noreferrer"&gt;TaxGuru, Section 393 of Income Tax Act 2025, Table 1 summary (secondary, cited only for the disputed table count)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.tdsman.com/2026/07/tds-on-fees-for-professional-and-technical-services-section-3931-194j/" rel="noopener noreferrer"&gt;TDSMAN, TDS on fees for professional and technical services (secondary, cited for the 6(iii).D(a)/(b) labelling)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/income-tax-act-202511" rel="noopener noreferrer"&gt;Income Tax Department, Income-tax Act 2025 page with the IT Bill comparison tool (primary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/w/rule-218-1" rel="noopener noreferrer"&gt;Income-tax Rules 2026, Rule 218, payment of tax deducted at source (primary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.incometaxindia.gov.in/w/rule-219-1" rel="noopener noreferrer"&gt;Income-tax Rules 2026, Rule 219, statements of tax deducted at source (primary; accessed 16 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Disclaimer:&lt;/strong&gt; This article is for informational purposes only and does not constitute financial, tax, or legal advice. Consult a qualified professional for advice specific to your situation.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/section-393-income-tax-act-2025-tds-section-mapping-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>section393</category>
      <category>194cnew</category>
      <category>194jnew</category>
      <category>tdssection</category>
    </item>
    <item>
      <title>AI Music Rules by Platform: October 2026 Matrix</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Thu, 15 Oct 2026 17:08:02 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/ai-music-rules-by-platform-october-2026-matrix-5108</link>
      <guid>https://dev.to/akaranjkar08/ai-music-rules-by-platform-october-2026-matrix-5108</guid>
      <description>&lt;p&gt;&lt;strong&gt;As of October 2026, no major streaming service pays out on fully AI-generated tracks the same way it pays human ones, and the rules differ sharply by platform: Bandcamp and Beatport ban them, TIDAL and Deezer accept them but stop paying royalties, and Spotify and YouTube accept them with disclosure.&lt;/strong&gt; Deezer says 13.4 million AI tracks were detected and tagged in 2025 and that up to 85% of streams on fully AI tracks were fraudulent.&lt;a href="https://newsroom-deezer.com/2026/07/ai-music-exceeds-50-percent-daily-uploads-deezer/" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; Below: one matrix covering nine platforms and four distributors, a short note per platform, a decision tree for hybrid versus fully AI releases, and the five mistakes that get catalogues pulled. Every claim carries a date. Anything I could not confirm from a primary source is left out.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Fully AI tracks are banned outright at Bandcamp (January 2026) and Beatport (August 2026).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TIDAL (policy of 29 June 2026) and Deezer tag fully AI tracks and exclude their streams from royalties or recommendations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spotify and YouTube do not ban AI music. They ask you to disclose it and they ban impersonation and spam.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;CD Baby will not distribute AI-generated content. TuneCore, LANDR and DistroKid take AI-assisted music with conditions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disclose accurately and keep a human performance or composition in the track. Silence is the riskiest option.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The matrix: nine platforms, four distributors
&lt;/h2&gt;

&lt;p&gt;Read the "Fully AI" column as what happens to a track with no meaningful human composition or performance. "Hybrid" means a human wrote, played or sang substantial parts and used AI for the rest. Dates in the last column are the month of the source I checked, not the month the rule began.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Fully AI track&lt;/th&gt;
&lt;th&gt;Disclosure / tagging&lt;/th&gt;
&lt;th&gt;Monetisation&lt;/th&gt;
&lt;th&gt;Enforcement&lt;/th&gt;
&lt;th&gt;Source date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Spotify | Allowed; no ban announced | AI credits via the DDEX standard, shown in Song Credits (beta since April 2026) | Disclosure does not down-rank; spam is tagged and no longer recommended | Unauthorised voice clones removed; spam filter for mass uploads, duplicates, SEO hacks, very short tracks | Sep 2025, updated Apr 2026 |&lt;/p&gt;

&lt;p&gt;| Apple Music | Labelling approach, not a ban | Optional AI Transparency Tags (artwork, track, composition, video) announced March 2026; later "Made With AI" labels promised | Not stated | Self-reported; no tag means treated as not AI | Mar 2026 |&lt;/p&gt;

&lt;p&gt;| YouTube / YouTube Music | Allowed; AI-generated music that is the focus of a video must be disclosed | "AI use" toggle in YouTube Studio; label may show in the player; auto-labels via C2PA metadata or detection | Disclosure alone does not limit audience or monetisation; mass-produced "inauthentic content" is not monetisable | Repeated non-disclosure risks removal or Partner Program suspension | Oct 2026 (help pages) |&lt;/p&gt;

&lt;p&gt;| Deezer | Accepted, but tagged and sidelined | Detection-based AI tag, applied at album level | Removed from algorithmic and editorial recommendations; fraudulent streams demonetised | Takedown for fraud-linked tracks and tracks unstreamed for 6+ months | Jul 2026 |&lt;/p&gt;

&lt;p&gt;| Beatport | Banned (fully or mostly AI) | AI-assisted tracks tagged at ingestion | Banned tracks never go on sale | Withheld at ingestion, rights holder notified; Beatdapp detection | Aug 2026 |&lt;/p&gt;

&lt;p&gt;| TIDAL | Accepted, labelled, unpaid | "AI" badge on wholly AI recordings; listeners can hide them | No royalties and no direct-to-fan sales on wholly AI music | Impersonation and fraud-linked AI music blocked or removed; distributors expected to flag | Jun-Jul 2026 |&lt;/p&gt;

&lt;p&gt;| Amazon Music | No detailed public policy found | No AI disclosure requirement announced | Not stated | Removals reported on IP flags; label partnerships against voice cloning | Mar 2026 (secondary) |&lt;/p&gt;

&lt;p&gt;| Bandcamp | Banned (wholly or in substantial part) | Not applicable; user reporting tools | Banned tracks cannot be sold | Removal on suspicion; AI impersonation of artists or styles prohibited | Jan 2026 |&lt;/p&gt;

&lt;p&gt;| SoundCloud | No AI-generated-music ban or label found | None found | Not stated | Terms: no training of generative models that replicate your voice or music without opt-in | 2025 terms |&lt;/p&gt;

&lt;p&gt;| DistroKid | Not stated in a primary source I could read | AI-assistance questions at upload, self-reported | Follows destination store rules | False answers can lead to copyright strikes (per DMN) | May 2026 |&lt;/p&gt;

&lt;p&gt;| TuneCore | Only if every GenAI tool used trained on fully licensed data | Under its GenAI Music Content Framework | Follows destination store rules | Older help pages still say 100% AI is not distributed | Oct 2026 (help pages) |&lt;/p&gt;

&lt;p&gt;| CD Baby | Not distributed, even with commercial rights from the generator | n/a | n/a | AI-generated content found later is removed from distribution | Oct 2026 (help pages) |&lt;/p&gt;

&lt;p&gt;| LANDR | Accepted with disclosure and monthly caps | Mandatory at upload; proof of rights if flagged | Ineligible for YouTube Content ID, TikTok and Meta monetisation | Detection technology; suspension up to six months for violations | Oct 2026 (help pages) |&lt;/p&gt;

&lt;p&gt;Two cells in that table are deliberately soft. Amazon Music and SoundCloud publish no AI-music rule that I could find, so "no policy found" is not "no rule". And TIDAL's own pages disagree internally, which I cover below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Platform by platform
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Spotify
&lt;/h3&gt;

&lt;p&gt;Spotify's September 2025 announcement set three pillars: an impersonation policy ("vocal impersonation is only allowed in music on Spotify when the impersonated artist has authorized the usage"), a music spam filter, and AI disclosures through DDEX.&lt;a href="https://newsroom.spotify.com/2025-09-25/spotify-strengthens-ai-protections/" rel="noopener noreferrer"&gt;[2]&lt;/a&gt; The page's update says a beta showing AI credits in Song Credits on mobile launched on 16 April, and that a missing credit does not prove no AI was used. Spotify says the policy is not about punishing artists who use AI responsibly or down-ranking disclosed tracks. Credit fields and the persona badge are covered in our &lt;a href="https://dev.to/blogs/spotify-ai-persona-badge-identity-stack-ai-assisted-artists-2026"&gt;persona badge deep-dive&lt;/a&gt; and the &lt;a href="https://dev.to/blogs/ai-music-metadata-release-checklist-ddex-ai-credits-spam-filter-2026"&gt;DDEX metadata checklist&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Apple Music
&lt;/h3&gt;

&lt;p&gt;Apple announced optional AI Transparency Tags on 4 March 2026 for labels and distributors, across artwork, track, composition and music video.&lt;a href="https://www.digitalmusicnews.com/2026/03/05/apple-music-ai-transparency-tags-requirement/" rel="noopener noreferrer"&gt;[3]&lt;/a&gt; A later Mixmag report quotes Apple telling partners that "as we implement Made With AI labels, content providers will be important partners," with no date given.&lt;a href="https://mixmag.asia/read/apple-music-begin-tagging-ai-generated-tracks-news" rel="noopener noreferrer"&gt;[4]&lt;/a&gt; Whether tags are mandatory yet is unsettled in the coverage I found, so tag anyway if your distributor offers the field.&lt;/p&gt;

&lt;h3&gt;
  
  
  YouTube and YouTube Music
&lt;/h3&gt;

&lt;p&gt;YouTube's help page requires disclosure of realistic AI content, and names "creates music that is the main focus of a video" among the triggers. You answer an "AI use" question in YouTube Studio. YouTube states disclosure alone does not limit a video's audience or affect monetisation eligibility, and it may label content automatically if it carries C2PA metadata or its systems detect AI.&lt;a href="https://support.google.com/youtube/answer/14328491" rel="noopener noreferrer"&gt;[5]&lt;/a&gt; Separately, the Partner Program page describes mass-produced, generic or repetitive content, including AI content from "generic or unoriginal templates", as not monetisable.&lt;a href="https://support.google.com/youtube/answer/1311392" rel="noopener noreferrer"&gt;[6]&lt;/a&gt; The risk is not the label. It is a channel of 200 near-identical AI tracks over still images.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deezer
&lt;/h3&gt;

&lt;p&gt;Deezer is the most transparent about numbers. Its July 2026 release says its detector claims 99.8% accuracy, that tracks flagged as AI are removed from algorithmic recommendations and left out of editorial playlists, and that it will remove AI tracks used for fraudulent streaming plus tracks unstreamed for six months or more.&lt;a href="https://newsroom-deezer.com/2026/07/ai-music-exceeds-50-percent-daily-uploads-deezer/" rel="noopener noreferrer"&gt;[1]&lt;/a&gt; The release also states the tool misses about 2 in 1,000 AI tracks and falsely flags fewer than 1 in 10,000 human ones. Note the release itself gives two different dates for the first AI tag, June 2025 and June 2026.&lt;/p&gt;

&lt;h3&gt;
  
  
  Beatport
&lt;/h3&gt;

&lt;p&gt;Beatport's updated Content Guidelines, reported on 13 August 2026, do not permit fully or mostly AI-generated tracks. They are withheld at ingestion and the rights holder is told. AI-assisted music is allowed if the finished track stays mostly human-made, and gets tagged.&lt;a href="https://synthtopia.com/content/2026/08/13/beatport-bans-ai-generated-music" rel="noopener noreferrer"&gt;[7]&lt;/a&gt; If you make DJ tools, this is the strictest store for a Suno-only catalogue.&lt;/p&gt;

&lt;h3&gt;
  
  
  TIDAL
&lt;/h3&gt;

&lt;p&gt;TIDAL published its AI policy on 29 June 2026. It says it will not knowingly pay royalties on music it identifies as wholly AI-generated, adds an "AI" badge, and expects distributors to flag AI content before delivery.&lt;a href="https://tidal.com/ai-policy" rel="noopener noreferrer"&gt;[8]&lt;/a&gt; Coverage notes that TIDAL's policy page defines AI music as "wholly or substantially generated" while its support FAQ applies actions only to wholly AI recordings for now, with substantial AI to follow. Plan for the broader definition.&lt;a href="https://www.musicbusinessworldwide.com/tidal-to-tag-fully-ai-generated-music-and-block-it-from-earning-royalties/" rel="noopener noreferrer"&gt;[9]&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Amazon Music and SoundCloud
&lt;/h3&gt;

&lt;p&gt;Neither publishes a dedicated AI-music policy I could find. Digital Music News describes Amazon as hosting AI tracks under a "catalog integrity" focus, with removals reported when IP flags are raised.&lt;a href="https://digitalmusicnews.com/2026/03/06/ai-rules-at-major-streaming-platforms" rel="noopener noreferrer"&gt;[10]&lt;/a&gt; SoundCloud's revised terms address training, not uploads: it will not train generative models that replicate your voice, music or likeness without explicit opt-in consent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bandcamp
&lt;/h3&gt;

&lt;p&gt;Bandcamp's 13 January 2026 post says music "generated wholly or in substantial part by AI" is not permitted, AI impersonation of artists or styles is strictly prohibited, and it may remove music it suspects is AI.&lt;a href="https://blog.bandcamp.com/2026/01/13/keeping-bandcamp-human/" rel="noopener noreferrer"&gt;[11]&lt;/a&gt; It never defines "substantial", and it describes no appeal route.&lt;/p&gt;

&lt;h3&gt;
  
  
  The distributor layer
&lt;/h3&gt;

&lt;p&gt;Distributors are where your release is first accepted or rejected, so their rules bind before any store sees the file. CD Baby's help centre says it does not distribute AI-generated content, even when commercially licensed. TuneCore's GenAI Music Content Framework allows GenAI music only when the tools used trained on fully licensed datasets, though older TuneCore pages still say 100% AI works are not distributed.&lt;a href="https://support.tunecore.com/hc/en-us/articles/46914166185236-TuneCore-s-GenAI-Music-Content-Framework" rel="noopener noreferrer"&gt;[12]&lt;/a&gt; LANDR requires disclosure at upload, caps monthly AI submissions (its help pages disagree on the number, so check your dashboard), and rules AI music out of Content ID, TikTok and Meta monetisation.&lt;a href="https://support.landr.com/hc/en-us/articles/23716156904983-Does-LANDR-accept-AI-generated-tracks" rel="noopener noreferrer"&gt;[13]&lt;/a&gt; DistroKid rolled out its AI-assistance questions in May 2026 and relies on self-reporting.&lt;a href="https://www.digitalmusicnews.com/2026/05/14/distrokid-ai-credit-disclosure-what-it-looks-like/" rel="noopener noreferrer"&gt;[14]&lt;/a&gt; The legal pressure on distributors is mapped in our &lt;a href="https://dev.to/blogs/umg-distrokid-lawsuit-distribution-risk-map-ai-musicians-2026"&gt;UMG v DistroKid risk map&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Release checklist per platform
&lt;/h2&gt;

&lt;p&gt;Run this once per release, in this order. The deep DDEX field walk-through lives in the &lt;a href="https://dev.to/blogs/ai-music-metadata-release-checklist-ddex-ai-credits-spam-filter-2026"&gt;metadata checklist&lt;/a&gt;, so this is the cross-platform layer only.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Spotify:&lt;/strong&gt; fill the distributor's AI-credit fields for vocals, instrumentation and post-production. Never release a voice that sounds like a named artist.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Apple Music:&lt;/strong&gt; tag artwork and track separately if the field exists. An AI cover is a disclosure item too.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;YouTube:&lt;/strong&gt; answer "AI use" Yes when AI music is the point of the video. Vary titles, art and content across uploads.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deezer:&lt;/strong&gt; assume detection. Expect no recommendation reach on a fully AI track.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Beatport and Bandcamp:&lt;/strong&gt; do not submit fully AI work. Keep stems or session files as proof of human performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;TIDAL:&lt;/strong&gt; assume a wholly AI track earns nothing and carries a badge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Distributor:&lt;/strong&gt; answer the AI questions truthfully. Check the store exclusions before ticking Content ID or TikTok.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Decision tree: hybrid or fully AI
&lt;/h2&gt;

&lt;p&gt;Work through these in order and stop at the first match.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Does the track imitate a named artist's voice or style closely? Stop. Spotify removes unauthorised clones, Bandcamp prohibits it, TIDAL blocks it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Did you write or perform a meaningful part (melody, lyrics, played instruments, recorded vocal)? If yes, treat it as hybrid and go to step 5.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is it a Suno or Udio generation with only light edits? It is fully AI for policy purposes. Skip Beatport, Bandcamp and CD Baby.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For the remaining stores, accept the sidelining: TIDAL pays nothing, Deezer will not recommend it. Release only where disclosure is honest and the goal is catalogue reach, not income. The &lt;a href="https://dev.to/blogs/fully-ai-music-peaked-hybrid-rule-siqa-mid-year-2026"&gt;hybrid rule post&lt;/a&gt; explains why this is a losing business.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pick a distributor that accepts your AI tools (CD Baby does not; TuneCore needs licensed-data tools).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disclose AI use in every field offered, release everywhere, and keep your project files.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are still drafting, the &lt;a href="https://dev.to/tools/suno-prompt-builder"&gt;Suno Prompt Builder&lt;/a&gt; helps you structure prompts so the human parts, such as your own lyrics, stay in the track. Playbook context is in &lt;a href="https://dev.to/blogs/ai-music-empire-suno-distrokid-playbook"&gt;the Suno and DistroKid playbook&lt;/a&gt;, and our &lt;a href="https://dev.to/product/regional-indian-music-pack-suno"&gt;Regional Indian Music Pack for Suno&lt;/a&gt; covers prompt templates for hybrid workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five mistakes that get catalogues pulled
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skipping the AI question.&lt;/strong&gt; Disclosure is self-reported at DistroKid, and DMN says dishonest answers could bring copyright strikes. A discovered lie costs more than the label.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mass uploading near-identical tracks.&lt;/strong&gt; Spotify's spam filter targets duplicates, mass uploads and artificially short tracks, and YouTube's inauthentic content rule targets templated output.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloning a real singer.&lt;/strong&gt; Allowed only with the artist's authorisation on Spotify; prohibited at Bandcamp; blocked at TIDAL.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assuming one distributor's yes is every store's yes.&lt;/strong&gt; LANDR says some destinations refuse AI content regardless of its policy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Letting dead tracks sit.&lt;/strong&gt; Deezer says it will remove AI tracks that have not been streamed for six months. An unplayed fully AI catalogue is the first thing to go.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Quick answers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I upload fully AI music to Spotify?
&lt;/h3&gt;

&lt;p&gt;Spotify announced no ban in its September 2025 policy and says it will not down-rank disclosed tracks. Impersonation and spam are what it removes. Your distributor may still refuse the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which platforms ban fully AI-generated music?
&lt;/h3&gt;

&lt;p&gt;Bandcamp (January 2026) and Beatport (August 2026) ban it. CD Baby will not distribute it. TIDAL and Deezer accept it but withhold pay or recommendations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does YouTube demonetise AI music if I tick the AI box?
&lt;/h3&gt;

&lt;p&gt;No. YouTube states that disclosure alone does not affect monetisation eligibility. The risk is mass-produced or repetitive content, which the Partner Program does not monetise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Will Deezer pay streams on my Suno track?
&lt;/h3&gt;

&lt;p&gt;Deezer says it demonetises fraudulent streams on fully AI tracks and drops detected AI tracks from recommendations. Legitimate streams on an AI-tagged track are not addressed in the release, so assume little reach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I have to disclose AI use if I only mastered with AI?
&lt;/h3&gt;

&lt;p&gt;Rules vary and distributors define the categories. Apple tags separate artwork, track, composition and video; Spotify's credits cover vocals, instrumentation and post-production. When unsure, disclose.&lt;/p&gt;

&lt;p&gt;These rules moved four times between January and August 2026. Recheck the linked pages before each release.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This article is for informational purposes only and does not constitute legal advice. Platform policies change often; confirm current terms with each platform and distributor before release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://newsroom-deezer.com/2026/07/ai-music-exceeds-50-percent-daily-uploads-deezer/" rel="noopener noreferrer"&gt;Deezer Newsroom, July 2026&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://newsroom.spotify.com/2025-09-25/spotify-strengthens-ai-protections/" rel="noopener noreferrer"&gt;Spotify Newsroom: AI protections&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.digitalmusicnews.com/2026/03/05/apple-music-ai-transparency-tags-requirement/" rel="noopener noreferrer"&gt;Digital Music News: Apple Music AI Transparency Tags&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://mixmag.asia/read/apple-music-begin-tagging-ai-generated-tracks-news" rel="noopener noreferrer"&gt;Mixmag: Apple Music Made With AI labels&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.google.com/youtube/answer/14328491" rel="noopener noreferrer"&gt;YouTube Help: disclosing altered or synthetic content&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.google.com/youtube/answer/1311392" rel="noopener noreferrer"&gt;YouTube Help: Partner Program policies&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://synthtopia.com/content/2026/08/13/beatport-bans-ai-generated-music" rel="noopener noreferrer"&gt;Synthtopia: Beatport bans AI-generated music&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://tidal.com/ai-policy" rel="noopener noreferrer"&gt;TIDAL AI Policy&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.musicbusinessworldwide.com/tidal-to-tag-fully-ai-generated-music-and-block-it-from-earning-royalties/" rel="noopener noreferrer"&gt;Music Business Worldwide: TIDAL&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://digitalmusicnews.com/2026/03/06/ai-rules-at-major-streaming-platforms" rel="noopener noreferrer"&gt;Digital Music News: AI rules at major platforms&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://blog.bandcamp.com/2026/01/13/keeping-bandcamp-human/" rel="noopener noreferrer"&gt;Bandcamp: Keeping Bandcamp Human&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.tunecore.com/hc/en-us/articles/46914166185236-TuneCore-s-GenAI-Music-Content-Framework" rel="noopener noreferrer"&gt;TuneCore GenAI Music Content Framework&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://support.landr.com/hc/en-us/articles/23716156904983-Does-LANDR-accept-AI-generated-tracks" rel="noopener noreferrer"&gt;LANDR Support: AI-generated tracks&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  14. &lt;a href="https://www.digitalmusicnews.com/2026/05/14/distrokid-ai-credit-disclosure-what-it-looks-like/" rel="noopener noreferrer"&gt;Digital Music News: DistroKid AI credit disclosure&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/ai-music-rules-by-platform-matrix-october-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aimusic</category>
      <category>aigenerated</category>
      <category>spotifyai</category>
      <category>deezerai</category>
    </item>
    <item>
      <title>Personal AI Agent on Cloudflare Free Tier 2026 (Code)</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Thu, 15 Oct 2026 16:44:53 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/personal-ai-agent-on-cloudflare-free-tier-2026-code-2i8i</link>
      <guid>https://dev.to/akaranjkar08/personal-ai-agent-on-cloudflare-free-tier-2026-code-2i8i</guid>
      <description>&lt;p&gt;&lt;strong&gt;A personal AI agent on Cloudflare's free tier costs $0 a month for about 70 Telegram conversations a day, and it deploys in 15 minutes.&lt;/strong&gt; The Workers free plan gives you 100,000 requests a day, Durable Objects give each chat its own SQLite memory, and Workers AI includes 10,000 free neurons daily. The first thing you run out of is neurons, not requests. Below you get the free quotas (checked against Cloudflare's docs on 15 October 2026), a Workers AI versus bring-your-own-key cost comparison in dollars, and a complete project: wrangler.jsonc, an Agents SDK class, and a Telegram webhook handler. It builds on the &lt;a href="https://dev.to/blogs/cloudflare-workers-guide-2026-build-deploy-scale-edge-functions-free"&gt;Cloudflare Workers guide&lt;/a&gt; and the &lt;a href="https://dev.to/blogs/cloudflare-agents-week-2026-agent-memory-developer-guide"&gt;Agents Week memory guide&lt;/a&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Free plan: 100,000 Worker requests a day, 10 ms CPU per request, 100,000 Durable Object requests a day.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Workers AI: 10,000 neurons a day free. At 30 chats a day on Llama 3.3 70B that is about 4,000 neurons, so $0.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bring your own Claude Haiku 5.5 key: about $0.36 a month at the same usage. Sonnet 5.5: about $7.20.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Per-chat memory lives in the agent's built-in SQLite. No D1 needed to start.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Outgrow order: neurons first, then Durable Object row writes, then CPU time.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the free plan gives you in October 2026
&lt;/h2&gt;

&lt;p&gt;These are the numbers that matter for an agent. All daily limits reset at 00:00 UTC.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Free quota&lt;/th&gt;
&lt;th&gt;What it does for the agent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Workers | 100,000 requests/day, 10 ms CPU per request, 50 subrequests, 5 cron triggers | Telegram webhook entry point |&lt;/p&gt;

&lt;p&gt;| Durable Objects | 100,000 requests/day, 13,000 GB-s/day, 5M rows read/day, 100,000 rows written/day, 5 GB SQLite | One agent instance per user, with memory |&lt;/p&gt;

&lt;p&gt;| Workers AI | 10,000 neurons/day | Model inference with no API key |&lt;/p&gt;

&lt;p&gt;| KV | 100,000 reads/day, 1,000 writes/day, 1 GB | Config and cached lookups |&lt;/p&gt;

&lt;p&gt;| D1 | 5M rows read/day, 100,000 rows written/day, 5 GB | Shared data across users |&lt;/p&gt;

&lt;p&gt;| R2 | 10 GB-month, 1M Class A and 10M Class B ops/month | Files the agent saves |&lt;/p&gt;

&lt;p&gt;| Vectorize | 5M stored and 30M queried dimensions/month | Semantic memory |&lt;/p&gt;

&lt;p&gt;| Queues | 10,000 operations/day, 24-hour retention | Background jobs (about 3,300 messages) |&lt;/p&gt;

&lt;p&gt;| Workflows | 10 ms CPU per step, 100 concurrent instances, 1,024 steps | Multi-step durable tasks |&lt;/p&gt;

&lt;p&gt;Two details save you debugging time. Free accounts can only create SQLite-backed Durable Objects, which is what the Agents SDK uses anyway[3]. And the 10 ms CPU cap counts compute only. Waiting on a model response, a KV read or a fetch does not count against it[1], so an agent that spends 2 seconds waiting on inference still uses a few milliseconds of CPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture in one paragraph
&lt;/h2&gt;

&lt;p&gt;Telegram sends each message to a Worker via webhook. The Worker checks a secret header, looks up an agent instance named after your chat ID, and calls a method on it. The agent stores the message in SQLite, calls a model with the last 12 messages, stores the reply, and returns it. The Worker posts the reply back through the Telegram Bot API. A cron schedule inside the agent sends you a morning summary. One Worker file, one Durable Object class.&lt;/p&gt;

&lt;h2&gt;
  
  
  The model decision: Workers AI or your own key
&lt;/h2&gt;

&lt;p&gt;Workers AI needs no key and no card. Its free allocation is 10,000 neurons a day, and Llama 3.3 70B fp8-fast is priced at 26,668 neurons per million input tokens and 204,805 per million output tokens[2]. The usage assumption below: 30 chats a day, 2,000 input tokens (system prompt plus history) and 400 output tokens per chat, over 30 days. That is 1.8M input and 0.36M output tokens a month.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Price per M tokens (in / out)&lt;/th&gt;
&lt;th&gt;Monthly cost at this usage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Workers AI, Llama 3.3 70B fp8-fast | 26,668 / 204,805 neurons | $0 (about 4,060 neurons a day, inside the 10,000 free) |&lt;/p&gt;

&lt;p&gt;| Workers AI, Llama 3.1 8B | 25,608 / 75,147 neurons | $0 (about 2,440 neurons a day) |&lt;/p&gt;

&lt;p&gt;| Claude Haiku 5.5 (own key) | $0.10 / $0.50 | $0.36 |&lt;/p&gt;

&lt;p&gt;| Claude Sonnet 5.5 (own key) | $2 / $10 | $7.20 |&lt;/p&gt;

&lt;p&gt;Workers AI pricing is from Cloudflare's pricing page; Claude pricing is from Anthropic's, both checked 15 October 2026[2][4]. The math for Haiku: 1.8 × $0.10 plus 0.36 × $0.50 equals $0.36. For Sonnet: 1.8 × $2 plus 0.36 × $10 equals $7.20.&lt;/p&gt;

&lt;p&gt;The practical split: start on Workers AI because it costs nothing and needs no secrets. Switch the single model call to Claude when answers need tool use or better reasoning. At $0.36 a month, Haiku 5.5 is cheaper than the time you would spend tuning a free model. To price your own workload, plug your token counts into the &lt;a href="https://dev.to/tools/agent-run-cost-simulator"&gt;agent run cost simulator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build it: 15-minute setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: project and dependencies
&lt;/h3&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;personal-agent &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;personal-agent
npm init &lt;span class="nt"&gt;-y&lt;/span&gt;
npm i agents
npm i &lt;span class="nt"&gt;-D&lt;/span&gt; wrangler typescript @cloudflare/workers-types
&lt;span class="nb"&gt;mkdir &lt;/span&gt;src
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install is a single package: &lt;code&gt;npm i agents&lt;/code&gt;[5]. Create a Telegram bot with &lt;a class="mentioned-user" href="https://dev.to/botfather"&gt;@botfather&lt;/a&gt; and keep the token. Send your new bot any message, then open &lt;code&gt;https://api.telegram.org/bot&amp;lt;TOKEN&amp;gt;/getUpdates&lt;/code&gt; and copy &lt;code&gt;message.chat.id&lt;/code&gt;. That is your owner ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: wrangler.jsonc
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "personal-agent",
  "main": "src/index.ts",
  "compatibility_date": "2026-10-01",
  "compatibility_flags": ["nodejs_compat"],
  "ai": { "binding": "AI" },
  "durable_objects": {
    "bindings": [{ "name": "PersonalAgent", "class_name": "PersonalAgent" }]
  },
  "migrations": [{ "tag": "v1", "new_sqlite_classes": ["PersonalAgent"] }]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The binding name becomes the property on &lt;code&gt;env&lt;/code&gt;, &lt;code&gt;class_name&lt;/code&gt; must match the exported class exactly, and &lt;code&gt;new_sqlite_classes&lt;/code&gt; is what enables SQLite storage[5].&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: the agent and the webhook (src/index.ts)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getAgentByName&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="s2"&gt;agents&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Ai&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;PersonalAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DurableObjectNamespace&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;WEBHOOK_SECRET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;OWNER_CHAT_ID&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Turn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assistant&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@cf/meta/llama-3.3-70b-instruct-fp8-fast&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;SYSTEM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;You are a terse personal assistant. Answer in under 120 words.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendTelegram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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://api.telegram.org/bot&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TELEGRAM_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/sendMessage`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&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;chat_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonalAgent&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;onStart&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`CREATE TABLE IF NOT EXISTS memory (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      role TEXT NOT NULL,
      content TEXT NOT NULL,
      ts INTEGER NOT NULL
    )`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Cron schedules are idempotent by default, so repeating this is safe.&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;30 3 * * *&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="s2"&gt;morningBrief&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;chatId&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`INSERT INTO memory (role, content, ts) VALUES ('user', &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;text&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="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="s2"&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;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
      SELECT role, content FROM (SELECT * FROM memory ORDER BY id DESC LIMIT 12)
      ORDER BY id`&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;SYSTEM&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="p"&gt;}))&lt;/span&gt; &lt;span class="k"&gt;as&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="kr"&gt;string&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;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The model returned nothing.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`INSERT INTO memory (role, content, ts) VALUES ('assistant', &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;reply&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="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="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="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;morningBrief&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="s2"&gt;`
      SELECT content FROM memory WHERE role = 'user' ORDER BY id DESC LIMIT 20`&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;messages&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;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;system&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;List open tasks and reminders from these notes in 5 lines max.&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;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&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="se"&gt;\n&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="k"&gt;as&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="kr"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendTelegram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nothing to report.&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;fetch&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="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&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;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ok&lt;/span&gt;&lt;span class="dl"&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&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="s2"&gt;X-Telegram-Bot-Api-Secret-Token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WEBHOOK_SECRET&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;forbidden&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;403&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;update&lt;/span&gt; &lt;span class="o"&gt;=&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;request&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="k"&gt;as&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&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;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;update&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;text&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;chatId&lt;/span&gt; &lt;span class="o"&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;update&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;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&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="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;chatId&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OWNER_CHAT_ID&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;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ok&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitUntil&lt;/span&gt;&lt;span class="p"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;agent&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;getAgentByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PersonalAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chatId&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;reply&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendTelegram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;chatId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reply&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ok&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="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;ExportedHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every piece here is a documented Agents SDK call. &lt;code&gt;this.sql&lt;/code&gt; is a tagged template for the instance's embedded SQLite, &lt;code&gt;getAgentByName(namespace, name)&lt;/code&gt; returns a typed stub you can call methods on, and &lt;code&gt;this.schedule(when, callback, payload)&lt;/code&gt; takes a delay in seconds, a &lt;code&gt;Date&lt;/code&gt;, or a cron string, with the callback given as a method name on the same class[6]. A callback name that does not exist throws, so keep the string and the method in sync.&lt;/p&gt;

&lt;p&gt;The cron string &lt;code&gt;30 3 * * *&lt;/code&gt; runs in UTC. That is 9:00 AM in India. Adjust it for your timezone.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: secrets, deploy, webhook
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx wrangler secret put TELEGRAM_TOKEN
npx wrangler secret put WEBHOOK_SECRET
npx wrangler secret put OWNER_CHAT_ID
npx wrangler deploy

curl &lt;span class="s2"&gt;"https://api.telegram.org/bot/setWebhook"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"url=https://personal-agent..workers.dev"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"secret_token="&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Telegram's &lt;code&gt;secret_token&lt;/code&gt; accepts 1 to 256 characters from A-Z, a-z, 0-9, underscore and hyphen, and arrives in the &lt;code&gt;X-Telegram-Bot-Api-Secret-Token&lt;/code&gt; header on every update[7]. That header check is the only thing stopping strangers from posting to your Worker URL, so do not skip it. The owner-ID check is the second lock: it means a leaked bot username cannot burn your neuron budget.&lt;/p&gt;

&lt;p&gt;The handler returns 200 immediately and does the work inside &lt;code&gt;ctx.waitUntil&lt;/code&gt;. Telegram retries a webhook that is slow to answer, and a 5-second model call would otherwise produce duplicate replies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Swapping in your own Claude key
&lt;/h2&gt;

&lt;p&gt;Replace the &lt;code&gt;env.AI.run&lt;/code&gt; call with a plain fetch to the Messages API. Store the key with &lt;code&gt;npx wrangler secret put ANTHROPIC_API_KEY&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://api.anthropic.com/v1/messages&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;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;x-api-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ANTHROPIC_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic-version&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="s2"&gt;2023-06-01&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="s2"&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="s2"&gt;application/json&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;body&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;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;claude-haiku-5-5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SYSTEM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;history&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;data&lt;/span&gt; &lt;span class="o"&gt;=&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;res&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="k"&gt;as&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="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&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;reply&lt;/span&gt; &lt;span class="o"&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;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No text returned.&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;The Haiku 5.5 API ID is &lt;code&gt;claude-haiku-5-5&lt;/code&gt; and Sonnet 5.5 is &lt;code&gt;claude-sonnet-5-5&lt;/code&gt;[8]. Add &lt;code&gt;ANTHROPIC_API_KEY: string&lt;/code&gt; to the &lt;code&gt;Env&lt;/code&gt; interface. The fetch wait does not count toward the 10 ms CPU cap, but parsing a large JSON response does, so keep &lt;code&gt;max_tokens&lt;/code&gt; modest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to keep memory: SQLite, D1 or KV
&lt;/h2&gt;

&lt;p&gt;Start with the agent's own SQLite, as in the code above. It is per-user, free to query from inside the class, and allows 5 GB total. Use D1 only when you need one query across several agents, such as an admin view of every chat. Skip KV for conversation logs: 1,000 writes a day to different keys is about 500 chats if you store two entries per turn. Use KV for read-heavy config you rarely change.&lt;/p&gt;

&lt;p&gt;For semantic recall over old notes, add Vectorize. The 5M stored-dimension allowance holds roughly 3,900 vectors at 1,280 dimensions each, and the 30M queried-dimension allowance covers about 23,000 queries a month at that size. A personal notebook will not hit either.&lt;/p&gt;

&lt;h2&gt;
  
  
  What breaks first when you outgrow free
&lt;/h2&gt;

&lt;p&gt;Ordered by how soon you hit them, on the usage assumption above:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workers AI neurons.&lt;/strong&gt; 10,000 a day is about 74 chats of 2,000 input and 400 output tokens on the 70B model. Long history windows eat it faster. Fix: switch to Llama 3.1 8B (about 120 chats a day), shorten history from 12 messages to 6, or move to Haiku at a few cents a week.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Durable Object row writes.&lt;/strong&gt; 100,000 a day. Each chat writes two memory rows plus index and schedule overhead, so you have headroom for thousands of chats. A chatty multi-user bot reaches this before requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CPU time.&lt;/strong&gt; 10 ms per request. Chat logic uses a fraction of that. It breaks when you add PDF parsing, image handling or crypto inside the request path. Move that work to a Workflow step, which has the same 10 ms free limit, or upgrade.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Requests.&lt;/strong&gt; 100,000 a day at roughly two requests per chat (Worker plus Durable Object) is about 50,000 chats. You will not get there alone.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When any limit trips, operations of that type start failing until midnight UTC. Your agent does not degrade gracefully, so wrap the model call in a try/catch and reply with a short "out of budget until 05:30 IST" message instead of silence. If your agent later needs to buy things or provision services on its own, the &lt;a href="https://dev.to/blogs/cloudflare-stripe-agent-provisioning-x402-mpp-agentic-commerce-guide-2026"&gt;Cloudflare and Stripe agent provisioning guide&lt;/a&gt; covers that path.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Is the Cloudflare Agents SDK free to use?
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;agents&lt;/code&gt; package is an npm library with no license fee. You pay only for the platform services it runs on, and all of those have free tiers: Workers, Durable Objects (SQLite-backed) and Workers AI.&lt;/p&gt;

&lt;h3&gt;
  
  
  How many Telegram messages can I send per day on the free tier?
&lt;/h3&gt;

&lt;p&gt;The binding constraint is Workers AI at 10,000 neurons a day, roughly 74 chats on Llama 3.3 70B with 2,000 input and 400 output tokens each. The request caps allow far more, about 50,000 chats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need a credit card for Workers AI?
&lt;/h3&gt;

&lt;p&gt;No. The 10,000 daily neurons are included on the free plan. The $0.011 per 1,000 neurons overage applies only on the paid Workers plan, so on free you hit a limit and wait for the reset.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can the agent run tasks while I am asleep?
&lt;/h3&gt;

&lt;p&gt;Yes. &lt;code&gt;this.schedule&lt;/code&gt; accepts a cron string and fires the named method on the agent without any incoming request.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is it safe to expose the Worker URL publicly?
&lt;/h3&gt;

&lt;p&gt;It is public by necessity, since Telegram must reach it. Protect it with the webhook secret header and the owner chat ID check. Never log message text to an external service, and keep API keys in &lt;code&gt;wrangler secret&lt;/code&gt;, never in wrangler.jsonc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workers AI or Claude for a personal agent?
&lt;/h3&gt;

&lt;p&gt;Workers AI if you want $0 and simple chat, notes and summaries. Claude Haiku 5.5 at about $0.36 a month for 30 chats a day when you need better instruction following. Sonnet 5.5 at about $7.20 a month only pays off for hard reasoning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers/platform/limits/" rel="noopener noreferrer"&gt;Cloudflare Workers limits (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers-ai/platform/pricing/" rel="noopener noreferrer"&gt;Cloudflare Workers AI pricing (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.cloudflare.com/durable-objects/platform/pricing/" rel="noopener noreferrer"&gt;Cloudflare Durable Objects pricing and free plan quotas (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;Anthropic Claude API pricing (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.cloudflare.com/agents/getting-started/add-to-existing-project/" rel="noopener noreferrer"&gt;Cloudflare Agents: add to an existing project (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://developers.cloudflare.com/agents/api-reference/schedule-tasks/" rel="noopener noreferrer"&gt;Cloudflare Agents: schedule tasks (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://core.telegram.org/bots/api#setwebhook" rel="noopener noreferrer"&gt;Telegram Bot API: setWebhook (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://platform.claude.com/docs/en/about-claude/models/overview" rel="noopener noreferrer"&gt;Anthropic models overview (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Every product mentioned is available at wowhow.cloud — pay once, ship forever.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/personal-ai-agent-cloudflare-free-tier-2026" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>personalai</category>
      <category>cloudflareagents</category>
      <category>cloudflareworkers</category>
      <category>workersai</category>
    </item>
    <item>
      <title>GST ITC Deadline 30 Nov 2026: FY 2025-26 Claim Guide</title>
      <dc:creator>Anup Karanjkar</dc:creator>
      <pubDate>Thu, 15 Oct 2026 16:18:16 +0000</pubDate>
      <link>https://dev.to/akaranjkar08/gst-itc-deadline-30-nov-2026-fy-2025-26-claim-guide-162</link>
      <guid>https://dev.to/akaranjkar08/gst-itc-deadline-30-nov-2026-fy-2025-26-claim-guide-162</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Input tax credit on any invoice or debit note dated in FY 2025-26 (1 April 2025 to 31 March 2026) is lost for good after the earlier of 30 November 2026 or the day you file GSTR-9 for that year. Reconcile GSTR-2B against your purchase books now, chase non-filing vendors, reverse what Rule 37A and Rule 37 require, and claim everything valid in the October 2026 GSTR-3B due 20 November. Quarterly (QRMP) filers: your last return before the deadline is the July-September GSTR-3B due 22 or 24 October, so reconcile this week. Do not file GSTR-9 early.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The ITC deadline for FY 2025-26 is 30 November 2026, and for many businesses it is earlier.&lt;/strong&gt; Section 16(4) of the CGST Act sets the cut-off at the earlier of 30 November following the end of the financial year or the date you furnish the annual return[1]. A business with ₹3.2 lakh of unclaimed credit sitting in unmatched or wrongly rejected invoices has 46 days from today, 15 October, to recover it. After that the credit becomes a permanent cost. This post covers what the section says, how to reconcile GSTR-2B, what to do about vendors who never filed, the 180-day payment rule, blocked credits, the Invoice Management System, a worked rupee example, and a dated calendar to 30 November.&lt;/p&gt;

&lt;h2&gt;
  
  
  What section 16(4) actually says
&lt;/h2&gt;

&lt;p&gt;Section 16(4) is a time bar. It does not grant credit. It says a registered person cannot take ITC on an invoice or debit note after the earlier of two dates: 30 November following the end of the financial year to which the invoice or debit note pertains, and the date of furnishing the annual return for that year[1].&lt;/p&gt;

&lt;p&gt;For FY 2025-26 that gives two possible cut-offs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Effective ITC cut-off for FY 2025-26 invoices&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| You file GSTR-9 after 30 November 2026 | 30 November 2026 |&lt;/p&gt;

&lt;p&gt;| You file GSTR-9 on, say, 10 November 2026 | 10 November 2026 |&lt;/p&gt;

&lt;p&gt;| You file GSTR-9 on 10 October 2026 | 10 October 2026 (already passed for you) |&lt;/p&gt;

&lt;p&gt;| Debit note dated 5 May 2026 (FY 2026-27) | Not in this window — runs to 30 November 2027 |&lt;/p&gt;

&lt;p&gt;Three points that trip people up.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The invoice date decides the financial year, not the date goods arrived or the vendor uploaded it. A 28 March 2026 invoice reported in May still belongs to FY 2025-26.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Filing GSTR-9 early shortens your own window. If your annual return is turned in before you have claimed everything, you have cut the deadline yourself. GSTR-9 for FY 2025-26 is normally due 31 December, so there is no reason to rush it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The time bar is on taking the credit in a return, so the GSTR-3B that carries the claim must be filed on or before the cut-off. The October 2026 GSTR-3B is due 20 November and is the last regular monthly return that fits. Quarterly (QRMP) filers get one return in the window, the July to September quarter, due on 22 or 24 October depending on state.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sections 16(5) and 16(6), inserted by the Finance (No. 2) Act 2024, gave one-time relief for FY 2017-18 to 2020-21 and for revoked cancellations[2]. They do not help FY 2025-26. The ICAI summary of the Finance Bill 2026 changes lists a rewrite of section 15(3)(b) on post-supply discounts but no change to section 16(4)[3]. I found no 2026 notification that moves this deadline, so plan around 30 November.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four conditions behind every credit
&lt;/h2&gt;

&lt;p&gt;Beating the time bar is only one test. Section 16(2) also requires a valid tax invoice or debit note, receipt of the goods or services, the supplier's invoice appearing in your GSTR-2B (the details furnished by the supplier in GSTR-1 or IFF), and actual payment of the tax to the government by the supplier[1]. You must also have filed your own GSTR-3B. Missing any one makes the credit contestable, however early you claim it.&lt;/p&gt;

&lt;p&gt;That is why reconciliation is the real job. The deadline just sets the clock.&lt;/p&gt;

&lt;h2&gt;
  
  
  GSTR-2B reconciliation: the workflow
&lt;/h2&gt;

&lt;p&gt;GSTR-2B is the static, auto-drafted statement of credit available to you for each month. Your purchase register is what you believe you are owed. The gap between them is your deadline risk. Run this in order.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: pull the data
&lt;/h3&gt;

&lt;p&gt;Download GSTR-2B for all twelve months of FY 2025-26, April 2025 to March 2026, plus the April to September 2026 statements, because late-reported FY 2025-26 invoices land in those. Export your purchase register for the same invoice dates. Clean vendor GSTIN typos first with the &lt;a href="https://dev.to/tools/gstin-validator"&gt;GSTIN validator&lt;/a&gt;; one wrong digit hides an invoice from any matcher.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: match on three keys
&lt;/h3&gt;

&lt;p&gt;Match on vendor GSTIN, invoice number (strip leading zeros, slashes and spaces) and invoice date. Then compare taxable value and each tax head.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: sort every row into one of five buckets
&lt;/h3&gt;

&lt;p&gt;This is where the GST ITC Rescue Workbook helps if you do not already have a matcher. It ships a GSTR-2B versus books matcher with section 16(4) flags and vendor follow-up email templates, and you can &lt;a href="https://dev.to/product/gst-itc-rescue-workbook-fy2025-26"&gt;see the GST ITC Rescue Workbook for FY 2025-26&lt;/a&gt; if you want a ready structure. A spreadsheet with VLOOKUP and a pivot works too. The buckets matter more than the tool.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Bucket&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;th&gt;Action by 20 November&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Matched | Present in books and GSTR-2B, values agree | Claim in GSTR-3B |&lt;/p&gt;

&lt;p&gt;| In books, not in 2B | Vendor has not reported, or reported under another GSTIN or date | Chase vendor for GSTR-1 or amendment by 11 November |&lt;/p&gt;

&lt;p&gt;| In 2B, not in books | Purchase not recorded, or not yours | Verify receipt; book it or reject in IMS |&lt;/p&gt;

&lt;p&gt;| Value or tax mismatch | Same invoice, different amounts or tax split | Vendor files an amendment, or claim the lower figure |&lt;/p&gt;

&lt;p&gt;| Date mismatch across year-end | Invoice dated March but booked April, or the reverse | Fix the FY tag; the invoice date governs |&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: book the cut-off vendors
&lt;/h3&gt;

&lt;p&gt;Rank vendors by credit at stake and call the top ten. A vendor who files GSTR-1 on 11 November for October can still add a September-dated or earlier invoice, and it will appear in the October GSTR-2B generated around 14 November. That is your last clean window, so the follow-up emails should go out this week, not in the second half of November.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vendors who have not filed: Rule 37A
&lt;/h2&gt;

&lt;p&gt;Rule 37A deals with a different problem. You claimed credit, the supplier reported the invoice, but the supplier never filed GSTR-3B. The rule applies when the supplier has not furnished GSTR-3B for the period by 30 September following the end of the financial year in which you took the ITC. You must then reverse that ITC while filing a GSTR-3B on or before 30 November following the end of that financial year, with interest under section 50 if you miss it[4].&lt;/p&gt;

&lt;p&gt;For FY 2025-26 credit, that means two dates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;30 September 2026 — the supplier's GSTR-3B status is tested on this date.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;30 November 2026 — the reversal must be made by then. In practice that is the October 2026 GSTR-3B, due 20 November.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;GSTN's advisory of 14 November 2023, issued when the rule first applied to FY 2022-23, says to report the reversal in Table 4(B)(2) of GSTR-3B[4]. Check that the table position still matches the current GSTR-3B form before filing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Re-availing the credit
&lt;/h3&gt;

&lt;p&gt;Rule 37A is a reversal, not a loss. If the supplier later files the GSTR-3B for that period, you can re-avail the amount in a later GSTR-3B[4]. Rule 37(4) says the section 16(4) time limit does not apply to re-availing credit that was reversed earlier, provided you originally took it within time[10]. Chasing the vendor is still worth doing, because it saves the reversal interest and the cash-flow hit. For vendors who filed GSTR-1 but not GSTR-3B, call before 20 November, not after.&lt;/p&gt;

&lt;p&gt;To work out the interest you will owe if you miss the reversal, use the &lt;a href="https://dev.to/tools/gst-late-fee-interest-calculator"&gt;GST late fee and interest calculator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 180-day payment rule: Rule 37
&lt;/h2&gt;

&lt;p&gt;The second reversal is about payment. You have to pay your supplier the invoice value plus tax within 180 days of the invoice date. Miss that and you reverse the ITC attributable to the unpaid portion, with interest under section 50, and you can take it back when you pay[5]. The rule does not apply to supplies where you pay tax under reverse charge[5].&lt;/p&gt;

&lt;p&gt;Take an invoice dated 10 April 2026. The 180 days run out on 7 October 2026. If it is still unpaid today, the credit on it has to be reversed. The reversal goes in the GSTR-3B for the tax period immediately following the 180-day period. Day 180 here is 7 October, so the rule's wording points to the November return (due 20 December). If you want to be safe, reverse it in the October return. Pay the vendor, and you can re-claim. Paying before day 180 is better still, because it avoids both the reversal and the interest.&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;Rule 37A&lt;/th&gt;
&lt;th&gt;Rule 37&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| Trigger | Supplier did not file GSTR-3B by 30 September after year-end | You did not pay the supplier within 180 days of invoice date |&lt;/p&gt;

&lt;p&gt;| Whose default | Vendor | You |&lt;/p&gt;

&lt;p&gt;| Reversal deadline | On or before 30 November following the year | GSTR-3B for the tax period immediately after the 180 days (safe option: the earlier return) |&lt;/p&gt;

&lt;p&gt;| Interest | Section 50, if reversal is late | Interest under section 50 (on utilised credit, per Rule 88B) |&lt;/p&gt;

&lt;p&gt;| Re-availment | When supplier files the GSTR-3B | When you pay the supplier |&lt;/p&gt;

&lt;p&gt;| Re-claim vs s.16(4) | Not time-barred (Rule 37(4)), if originally claimed in time | Not time-barred (Rule 37(4)), if originally claimed in time |&lt;/p&gt;

&lt;h2&gt;
  
  
  Blocked credits under section 17(5)
&lt;/h2&gt;

&lt;p&gt;Some credit is never available, however early you claim. These are the items clients most often try to claim. Check each against the section before you put them in GSTR-3B[1]:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Motor vehicles for carrying fewer than 13 people, unless used for the specified purposes such as further supply, passenger transport or driver training (section 17(5)(a)).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Food and beverages, outdoor catering, beauty treatment, health services, cosmetic and plastic surgery, with a narrow exception where the same category of service is your outward supply (17(5)(b)).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Works contract services and goods or services used for constructing an immovable property, other than plant and machinery (17(5)(c) and (d)).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Goods or services used for personal consumption (17(5)(g)).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Goods lost, stolen, destroyed, written off or given as gifts or free samples (17(5)(h)).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tax paid on a section 74 demand for periods up to FY 2023-24 (17(5)(i)).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Blocked items that sit in GSTR-2B often flow into GSTR-3B by habit. Strip them out; it is cheaper than reversing them with interest later. Check the tax value of borderline invoices with the &lt;a href="https://dev.to/tools/gst-calculator"&gt;GST calculator&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  IMS: accept, reject, pending
&lt;/h2&gt;

&lt;p&gt;The Invoice Management System went live from the October 2024 tax period. It lets you mark each supplier-reported record as accepted, rejected or pending before GSTR-2B is finalised[6]. The practical effects for this deadline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Accepted records flow into GSTR-2B as available credit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rejected records are excluded from your ITC and go back to the supplier to amend.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Records with no action are treated as accepted when GSTR-2B is generated.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pending records are held back and, per ClearTax's summary of the process, are not acted on until the section 16(4) limit[7].&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The September 2025 GSTN advisory changed pending for some document types. From the October 2025 tax period, recipients can keep specified records pending for one tax period (one month for monthly filers, one quarter for quarterly filers). Those records include credit notes and certain downward amendments of invoices or debit notes[8]. The same advisory added an ITC declaration facility, so you can state the ITC actually availed and the amount reversed, and optional remarks on rejected or pending records. In April 2026, GSTN added an Excel-based IMS offline tool for acting on invoices individually or in bulk[9].&lt;/p&gt;

&lt;h3&gt;
  
  
  How IMS can cost you credit before 30 November
&lt;/h3&gt;

&lt;p&gt;Pending is not a safe parking lot for plain invoices. An invoice you leave pending past the cut-off cannot be claimed. A rejected invoice that you rejected by mistake is the other trap, because it vanishes from GSTR-2B. If you rejected something by mistake, you can change the action until you file that period's GSTR-3B, then recompute GSTR-2B. If the supplier has already filed GSTR-3B, the 19 June 2025 GSTN advisory applies: the supplier re-reports the same document in GSTR-1A or a later amendment table and you accept it in IMS[7]. Start that now, because it needs the vendor to act.&lt;/p&gt;

&lt;p&gt;A clean routine for the next five weeks: open IMS on 1 November, clear every "no action" row on FY 2025-26 invoices, accept what matches, reject what is not yours, and leave nothing pending that you intend to claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worked example: ₹3.2 lakh at risk
&lt;/h2&gt;

&lt;p&gt;This is an illustrative SME, a Pune trading business with ₹4.8 crore turnover. At that size it is QRMP-eligible, so its last return before the deadline could be the July-September quarter due 22 or 24 October. Its FY 2025-26 reconciliation on 15 October 2026 shows these gaps. All figures are ITC in rupees.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Line&lt;/th&gt;
&lt;th&gt;Issue&lt;/th&gt;
&lt;th&gt;ITC (₹)&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| A | Vendor X: 21 invoices in books, not in 2B | 1,32,000 | At risk, lost after 30 Nov |&lt;/p&gt;

&lt;p&gt;| B | Vendor Y: 11 invoices in books, not in 2B | 78,500 | At risk, lost after 30 Nov |&lt;/p&gt;

&lt;p&gt;| C | Vendor Z: 6 invoices in books, not in 2B | 36,000 | At risk, lost after 30 Nov |&lt;/p&gt;

&lt;p&gt;| D | Invoices rejected in IMS by mistake | 74,200 | Recoverable only if corrected |&lt;/p&gt;

&lt;p&gt;| E | Credit claimed, vendor GSTR-3B unfiled at 30 Sep (Rule 37A) | 1,18,000 | Reverse by 30 Nov |&lt;/p&gt;

&lt;p&gt;| F | Invoices unpaid beyond 180 days (Rule 37) | 43,500 | Reverse or pay |&lt;/p&gt;

&lt;p&gt;| G | Staff lunch and catering, wrongly in claim (17(5)(b)) | 31,800 | Do not claim |&lt;/p&gt;

&lt;p&gt;The math:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Credit that disappears for good if nothing happens: A + B + C = 1,32,000 + 78,500 + 36,000 = ₹2,46,500.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the wrongly rejected lines D = ₹74,200. Total at risk = ₹2,46,500 + ₹74,200 = &lt;strong&gt;₹3,20,700&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reversal exposure, recoverable later when the vendor files or you pay: E + F = 1,18,000 + 43,500 = ₹1,61,500.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove G from the claim: ₹31,800 less in GSTR-3B.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two results stand out. The first is that line A alone is 41% of the total at-risk figure (1,32,000 ÷ 3,20,700), and it comes down to a single vendor filing. The second is that paying the ₹43,500 of old invoices eliminates a reversal and its interest at once. In this business, a day spent on vendor X is worth more than a week of internal tidying.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mistakes CAs see every November
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Filing GSTR-9 early.&lt;/strong&gt; It resets the cut-off to that date. Hold the annual return until every claim is in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treating 30 November as the day to start.&lt;/strong&gt; The GSTR-3B for October is due 20 November. The real deadline for vendor action is the 11 November GSTR-1 date.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Assuming GSTR-2B equals proof of payment.&lt;/strong&gt; A listed invoice still falls under Rule 37A if the vendor's GSTR-3B is missing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Letting IMS auto-accept.&lt;/strong&gt; Deemed acceptance pulls in invoices that are wrong, blocked or not yours.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Forgetting to re-avail.&lt;/strong&gt; Once the vendor files or you pay, the reversed credit stays in your ledger of lost money unless you claim it back in a later GSTR-3B.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Action calendar: 15 October to 30 November 2026
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;| 15 to 17 October | Download GSTR-2B for April 2025 to September 2026; export the purchase register; run the match |&lt;/p&gt;

&lt;p&gt;| 18 to 19 October | Send written mismatch lists to the top ten vendors by credit value |&lt;/p&gt;

&lt;p&gt;| 20 October | September 2026 GSTR-3B due for monthly filers; claim every matched, eligible FY 2025-26 credit |&lt;/p&gt;

&lt;p&gt;| 22 or 24 October | QRMP quarterly GSTR-3B (state-based date); your last return before the deadline, so reconcile this week |&lt;/p&gt;

&lt;p&gt;| 25 to 31 October | Pay unpaid vendors older than 120 days to avoid Rule 37 reversals (invoices dated before about 3 June 2026 hit day 180 before 30 November) |&lt;/p&gt;

&lt;p&gt;| 1 to 7 November | Clear IMS: accept, reject, remove pending on FY 2025-26 rows |&lt;/p&gt;

&lt;p&gt;| 11 November | Vendors' October GSTR-1 due; the last clean date for late invoices to appear |&lt;/p&gt;

&lt;p&gt;| 14 November | October GSTR-2B generates; re-run the match on the new statement |&lt;/p&gt;

&lt;p&gt;| 15 to 19 November | Finalise Rule 37A reversals and Rule 37 reversals; prepare the claim |&lt;/p&gt;

&lt;p&gt;| 20 November | October 2026 GSTR-3B due; claim, reverse, pay |&lt;/p&gt;

&lt;p&gt;| 30 November | Section 16(4) cut-off for FY 2025-26 credit |&lt;/p&gt;

&lt;p&gt;Put these dates into the &lt;a href="https://dev.to/tools/gst-compliance-calendar-2026"&gt;GST compliance calendar for 2026&lt;/a&gt; so reminders reach the whole accounts team. Verify every due date on the GST portal, because extensions are common.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is the last date to claim ITC for FY 2025-26?
&lt;/h3&gt;

&lt;p&gt;The earlier of 30 November 2026 and the date you file GSTR-9 for FY 2025-26, under section 16(4) of the CGST Act. If you file the annual return after 30 November, the date is 30 November.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I claim FY 2025-26 ITC in the November 2026 return?
&lt;/h3&gt;

&lt;p&gt;No. The November return is filed in December, after the cut-off. The October 2026 GSTR-3B, due on 20 November, is the last monthly return that can carry the claim.&lt;/p&gt;

&lt;h3&gt;
  
  
  My vendor has not filed GSTR-3B. Do I lose the credit?
&lt;/h3&gt;

&lt;p&gt;You reverse it if the vendor's GSTR-3B for the period was not filed by 30 September 2026, using Rule 37A, and the reversal is due by 30 November 2026. You can re-avail it in a later GSTR-3B once the vendor files. Rule 37(4) keeps that re-claim outside the section 16(4) time bar, as long as the original claim was in time.&lt;/p&gt;

&lt;h3&gt;
  
  
  What happens if I do not pay a supplier within 180 days?
&lt;/h3&gt;

&lt;p&gt;You must reverse the credit on the unpaid amount with interest under section 50. You can re-claim it after paying; Rule 37(4) keeps the re-claim outside the time bar. Reverse-charge supplies are outside Rule 37.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does IMS change the section 16(4) deadline?
&lt;/h3&gt;

&lt;p&gt;No. IMS controls what flows into GSTR-2B and GSTR-3B. The deadline is unchanged, and a record left pending or wrongly rejected can still expire with the time bar.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I file GSTR-9 before 30 November?
&lt;/h3&gt;

&lt;p&gt;Not unless every FY 2025-26 claim is already in. Filing GSTR-9 sets the cut-off at that filing date, which can be earlier than 30 November.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cbic-gst.gov.in/pdf/circular-237-31-2024-GST.pdf" rel="noopener noreferrer"&gt;CBIC, Circular 237/31/2024-GST, reproducing section 16(4) to (6) of the CGST Act (accessed 15 October 2026)&lt;/a&gt;. The 30 November date came in through Finance Act 2022 section 100(b), in force from 1 October 2022 (Notification 18/2022-CT).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cbic-gst.gov.in/pdf/circular-237-31-2024-GST.pdf" rel="noopener noreferrer"&gt;CBIC, Circular 237/31/2024-GST on sections 16(5) and 16(6) (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cajournal.icai.org/article-details/gst-amendments-proposed-through-the-finance-bill-2026" rel="noopener noreferrer"&gt;ICAI, GST Amendments Proposed through the Finance Bill 2026 (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.taxmann.com/post/blog/analysis-understanding-rule-37a-and-gstn-advisory/" rel="noopener noreferrer"&gt;Taxmann, Understanding Rule 37A and the GSTN advisory of 14 November 2023 (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://gstcouncil.gov.in/sites/default/files/2024-05/ct26-2022.pdf" rel="noopener noreferrer"&gt;Notification 26/2022-Central Tax, 26 December 2022, inserting Rule 37A (accessed 15 October 2026)&lt;/a&gt;; &lt;a href="https://gstcouncil.gov.in/sites/default/files/2024-04/01062021-cgst-rules-2017-part-a-rules.pdf" rel="noopener noreferrer"&gt;CGST Rules 2017, rule 37(4) (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cleartax.in/s/rule-37-of-cgst-sgst-rules-itc-reversal-180-days" rel="noopener noreferrer"&gt;ClearTax, Rule 37 of the CGST Rules: ITC reversal on non-payment within 180 days (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.gstcouncil.gov.in/sites/default/files/2026-05/newsletter_april_issue.pdf" rel="noopener noreferrer"&gt;GST Council Secretariat, April 2026 newsletter: IMS background and offline tool (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://cleartax.in/s/invoice-management-system-ims-process-flow" rel="noopener noreferrer"&gt;ClearTax, Invoice Management System process flow (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.ey.com/en_in/technical/alerts-hub/2025/09/gstn-issues-advisory-on-the-changes-introduced-in-the-invoice-management-system" rel="noopener noreferrer"&gt;EY Tax Alert, GSTN advisory of 23 September 2025 on IMS changes (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://tutorial.gst.gov.in/downloads/news/advisory_on_ims_offline_tool_23rd_april_2026.pdf" rel="noopener noreferrer"&gt;GSTN, advisory on the IMS Offline Tool, April 2026 (accessed 15 October 2026)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This article is for informational purposes only and does not constitute financial, tax, or legal advice. Consult a qualified professional for advice specific to your situation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Every product mentioned is available at wowhow.cloud — pay once, ship forever.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://wowhow.cloud/blogs/gst-itc-deadline-30-november-2026-fy-2025-26-claim-guide" rel="noopener noreferrer"&gt;wowhow.cloud&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gstitc</category>
      <category>section164</category>
      <category>gstr2breconciliation</category>
      <category>rule37a</category>
    </item>
  </channel>
</rss>
