惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
Check Point Blog
美团技术团队
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
V
Visual Studio Blog
Google DeepMind News
Google DeepMind News
Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
有赞技术团队
有赞技术团队
T
The Blog of Author Tim Ferriss
WordPress大学
WordPress大学
月光博客
月光博客
宝玉的分享
宝玉的分享
小众软件
小众软件
MongoDB | Blog
MongoDB | Blog
Apple Machine Learning Research
Apple Machine Learning Research
A
About on SuperTechFans
J
Java Code Geeks
博客园_首页
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
N
Netflix TechBlog - Medium
Vercel News
Vercel News
博客园 - 聂微东

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Australian ABN validation for SaaS developers
BitOwl · 2026-06-21 · via DEV Community

Selling to Australian businesses and never heard of ABN? That's fine, most people building global SaaS haven't. But once you have an Australian business customer, they're going to ask for it on the invoice. And if you don't collect it during checkout, you're adding friction later.

Here's the short version:

What is an ABN?

ABN stands for "Australian Business Number". It's an 11-digit identifier issued by the Australian Business Register, and basically every business entity in Australia has one. It goes on invoices. Australian businesses use it to claim GST credits back, so your B2B customers will want to provide it.

Legally, businesses are required to include their ABN on invoices over AUD 82.50. For a SaaS subscription that's pretty much every invoice.

Validating ABN:s

The official path is the ABR lookup API. It's free, but it requires registering for a developer GUID, and the response format is XML. There's also a checksum algorithm specific to ABN's that you'd need to implement for format validation before even hitting the registry.

Skip all of that. I use TaxVett for this:

curl -X POST https://api.taxvett.com/v1/validate \
  -H "X-Api-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"number": "51824753556", "country": "AU"}'

Response:

{
  "valid": true,
  "number": "51824753556",
  "country": "AU",
  "regime": "au_abn",
  "verification_method": "live_registry",
  "company_name": "Apple Pty Ltd"
}

The lookup goes against the live ABR registry, so you get the registered business name back too. This is useful for pre-filling the company name field in your checkout, or displaying "Invoices will be issued to: [company name]" before the customer confirms.

A checkout pattern that works:

Here's how I wire this into a checkout form. The ABN field validates on blur. No submit needed:

// React (works with Next.js, Remix, Astro API routes, etc.)

async function validateABN(abn: string): Promise<{
  valid: boolean;
  companyName?: string;
}> {
  const normalised = abn.replace(/\s/g, "");

  const res = await fetch("/api/validate-abn", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ abn: normalised }),
  });

  return res.json();
}

// In your form component:
function ABNField() {
  const [status, setStatus] = useState<"idle" | "valid" | "invalid">("idle");
  const [companyName, setCompanyName] = useState<string>();

  async function handleBlur(e: React.FocusEvent<HTMLInputElement>) {
    const abn = e.target.value.trim();
    if (!abn) return;

    const result = await validateABN(abn);
    setStatus(result.valid ? "valid" : "invalid");
    setCompanyName(result.companyName);
  }

  return (
    <div>
      <input
        type="text"
        name="abn"
        placeholder="51 824 753 556"
        onBlur={handleBlur}
      />
      {status === "valid" && companyName && (
        <p className="text-sm text-green-600"> {companyName}</p>
      )}
      {status === "invalid" && (
        <p className="text-sm text-red-600">
          ABN not found. Check the number and try again.
        </p>
      )}
    </div>
  );
}

The server route that proxies the validation (keeps your API key out of the browser):

// pages/api/validate-abn.ts or app/api/validate-abn/route.ts

export async function POST(req: Request) {
  const { abn } = await req.json();

  const res = await fetch("https://api.taxvett.com/v1/validate", {
    method: "POST",
    headers: {
      "X-Api-Key": process.env.TAXVETT_API_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ number: abn, country: "AU" }),
  });

  if (res.status === 422) {
    return Response.json({ valid: false });
  }

  const data = await res.json();
  return Response.json({
    valid: data.valid,
    companyName: data.company_name,
  });
}

ABN format notes

ABNs are 11 digits. They're often written with spaces: 51 824 753 556. Strip spaces before sending. The checksum validation catches a lot of typos before the request even reaches the registry, and the API returns a 422 for those cases so you can show a useful error without burning a lookup.

What about GST registration?

Not every ABN holder is registered for GST. Sole traders under the AUD 75,000 annual revenue threshold don't have to be. The ABR API returns GST status if you need it, but for a global SaaS checkout, validating the ABN is enough. It confirms the business exists and is registered in Australia.

Pros and cons

Pros: free tier covers development and early production (500 req/month), no XML or ABR developer GUID, returns the registered company name which you can show in checkout

Cons: paid at higher volumes (from 9 EUR/month), adds a third-party request to your checkout flow so handle timeouts gracefully

Also works for EU and UK

If you're selling globally, the same endpoint handles UK VAT, all 27 EU member states, Norway and Singapore too. One API key, same response shape. The regime field tells you which registry handled the lookup (au_abn, eu_vat, gb_vat, etc.).

There's a practical comparison of EU VAT validation options and a guide to UK VAT post-Brexit if you need those regions covered too.

GLHF coding