Next.js ile Xero Bağlantısı Nasıl Yapılır?

By Codefacture6 dk okuma

Next.js ile Xero Bağlantısı Nasıl Yapılır?

 

Xero, başta Birleşik Krallık, Avustralya ve Yeni Zelanda olmak üzere çok sayıda küçük ve orta ölçekli işletmenin tercih ettiği muhasebe platformudur. Next.js ile geliştirilen SaaS ürünleri ve iç araçlar için Xero'ya bağlanmak; faturaların otomatik oluşturulması, kişilerin senkronize kalması ve finansal verilerin manuel iş gerektirmeden akması demektir. Next.js bu iş için güçlü bir seçimdir, çünkü OAuth akışı, API çağrıları ve webhook'lar uygulamanın geri kalanıyla birlikte route handler'larda yer alabilir. Asıl zorluk mimaridir: serverless fonksiyonlar istekler arasında bellekte hiçbir şey tutmaz, bu yüzden token'lar ve bağlantı bilgileri doğru şekilde saklanmalı ve yenilenmelidir. Bu rehberde Xero'yu Next.js App Router ile adım adım bağlayacak, her aşama için kod örnekleri paylaşacağız.

 

Başlamadan Önce

İşe Xero geliştirici portalında bir uygulama oluşturarak başlayın. Web app türünü seçin ve callback adresinizi ekleyin; örneğin yerel geliştirme için http://localhost:3000/api/xero/callback. Portal size bir istemci kimliği (client ID) ve istemci anahtarı (client secret) verir. Geliştirme sırasında, örnek verilerle gelen ve gerçek defterlere dokunmadan test yapmak için ideal olan Xero demo şirketine bağlanabilirsiniz.

Bilinmesi gereken önemli ve yeni bir değişiklik var: 2 Mart 2026 ve sonrasında oluşturulan uygulamalar artık geniş kapsamlı accounting.transactions scope'unu talep edemez. Bunun yerine accounting.invoices veya accounting.payments gibi granüler scope'ları, yalnızca uygulamanın gerçekten ihtiyaç duyduğu izinleri seçerek talep etmeleri gerekir. Mevcut uygulamaların geçiş için Eylül 2027'ye kadar süresi var. Bunu göz önünde bulundurarak resmi Xero Node.js SDK'sını kurun ve ortam değişkenlerinizi ayarlayın.

npm install xero-node server-only
# .env.local
XERO_CLIENT_ID=...
XERO_CLIENT_SECRET=...
XERO_REDIRECT_URI=http://localhost:3000/api/xero/callback
XERO_WEBHOOK_KEY=...

 

Xero İstemcisini Yapılandırmak

Xero SDK'sı token'ları istemci nesnesinin içinde tutar. Bu, sürekli çalışan bir Node.js sunucusunda sorun yaratmaz; ancak serverless bir Next.js dağıtımında her istek yeni bir ortamda çalışabilir. Güvenli yaklaşım, tek bir global nesneyi paylaşmak yerine her istek için yeni bir istemci oluşturmak ve token'ları veritabanınızdan yüklemektir. Kısa ömürlü erişim token'ının süresi dolduktan sonra bağlantıyı canlı tutan yenileme token'ını alabilmek için offline_access scope'u gereklidir.

// lib/xero.ts
import "server-only";
import { XeroClient } from "xero-node";

// Create a fresh client per request: serverless functions share no memory
export function createXeroClient() {
  return new XeroClient({
    clientId: process.env.XERO_CLIENT_ID!,
    clientSecret: process.env.XERO_CLIENT_SECRET!,
    redirectUris: [process.env.XERO_REDIRECT_URI!],
    scopes: [
      "openid",
      "profile",
      "email",
      "accounting.contacts",
      "accounting.invoices",
      "offline_access",
    ],
  });
}

 

OAuth 2.0 Akışını Kurmak

Yetkilendirme akışı için iki route handler gerekir. İlki Xero onay adresini oluşturur ve kullanıcıyı oraya yönlendirir. Onay ekranında kullanıcı Xero'ya giriş yapar, talep edilen izinleri inceler ve hangi organizasyonları bağlayacağını seçer. Üretim ortamında, siteler arası istek sahteciliğine (CSRF) karşı korunmak için istemci yapılandırmasına bir state değeri ekleyin ve bunu callback'te doğrulayın.

// app/api/xero/connect/route.ts
import { NextResponse } from "next/server";
import { createXeroClient } from "@/lib/xero";

export async function GET() {
  const xero = createXeroClient();
  const consentUrl = await xero.buildConsentUrl();
  return NextResponse.redirect(consentUrl);
}

İkinci route callback'i karşılar. Yetkilendirme kodunu token'larla takas eder, tenant olarak adlandırılan bağlı organizasyonların listesini alır ve token setini tenant kimliğiyle birlikte saklar. Her Accounting API çağrısı hangi tenant'ı hedeflediğini belirtmek zorunda olduğu için bu kimliği saklamak şarttır.

// app/api/xero/callback/route.ts
import { NextResponse } from "next/server";
import { createXeroClient } from "@/lib/xero";
import { saveXeroConnection } from "@/lib/db";

export async function GET(req: Request) {
  const xero = createXeroClient();
  await xero.initialize();

  const tokenSet = await xero.apiCallback(req.url);
  await xero.updateTenants(false);

  const tenant = xero.tenants[0];
  await saveXeroConnection({
    tenantId: tenant.tenantId,
    tenantName: tenant.tenantName,
    tokenSet,
  });

  return NextResponse.redirect(new URL("/settings/integrations", req.url));
}

 

API Çağrıları Yapmak ve Token'ları Yenilemek

Saklanan bir bağlantıyla, sunucu tarafındaki her kod Accounting API'yi çağırabilir: route handler'lar, server action'lar veya arka plan işleri. Her çağrıdan önce token setini yükleyin, erişim token'ının süresinin dolup dolmadığını kontrol edin ve gerekiyorsa yenileyin. Yenileme işlemi yeni bir yenileme token'ı ürettiği için güncellenen token seti hemen kaydedilmelidir. Aşağıdaki örnek bir taslak satış faturası oluşturur; işletme faturaları otomatik onaylamaya hazır olana kadar bu güvenli bir varsayılandır.

// lib/xero-invoices.ts
import "server-only";
import { Invoice, LineAmountTypes } from "xero-node";
import { createXeroClient } from "@/lib/xero";
import { getXeroConnection, saveXeroConnection } from "@/lib/db";

export async function createDraftInvoice(contactId: string, amount: number) {
  const connection = await getXeroConnection();
  const xero = createXeroClient();
  await xero.initialize();
  xero.setTokenSet(connection.tokenSet);

  if (xero.readTokenSet().expired()) {
    const tokenSet = await xero.refreshToken();
    await saveXeroConnection({ ...connection, tokenSet });
  }

  const invoice: Invoice = {
    type: Invoice.TypeEnum.ACCREC,
    contact: { contactID: contactId },
    lineAmountTypes: LineAmountTypes.Exclusive,
    status: Invoice.StatusEnum.DRAFT,
    lineItems: [
      {
        description: "Consulting services",
        quantity: 1,
        unitAmount: amount,
        accountCode: "200",
      },
    ],
  };

  const { body } = await xero.accountingApi.createInvoices(connection.tenantId, {
    invoices: [invoice],
  });

  return body.invoices?.[0];
}

 

Xero Webhook'larını Almak

Uygulamanız, değişiklikleri sürekli sorgulamak yerine oluşturulan veya güncellenen kişiler ve faturalar gibi olaylar için Xero webhook'larına abone olabilir. Her webhook isteği, webhook anahtarınızla oluşturulmuş ham gövdenin HMAC-SHA256 özeti olan bir x-xero-signature başlığı taşır. Adresi ilk kaydettiğinizde Xero bir intent-to-receive doğrulaması gönderir: route'unuz doğru imzalanmış isteklere 200, yanlış imzalanmış olanlara 401 dönmelidir; aksi halde abonelik aktive edilmez.

Xero hızlı yanıt bekler; bu yüzden işleyici yalnızca imzayı doğrulamalı, olayları kuyruğa almalı ve yanıt dönmelidir. Webhook içerikleri tam kayıtlar yerine değişen kaynaklara referanslar içerdiğinden, güncel veriyi API'den bir arka plan işi çekmelidir.

// app/api/webhooks/xero/route.ts
import crypto from "node:crypto";

export const runtime = "nodejs";

export async function POST(req: Request) {
  const body = await req.text();
  const signature = req.headers.get("x-xero-signature") ?? "";

  const expected = crypto
    .createHmac("sha256", process.env.XERO_WEBHOOK_KEY!)
    .update(body)
    .digest("base64");

  const valid =
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

  if (!valid) {
    return new Response(null, { status: 401 });
  }

  const { events } = JSON.parse(body);
  // Queue the events and respond quickly; fetch full records in a background job
  await enqueueXeroEvents(events);

  return new Response(null, { status: 200 });
}

 

Üretim İçin En İyi Uygulamalar

Xero, dakika başına ve günlük çağrı limitlerinin yanı sıra eşzamanlı istek limiti de dahil olmak üzere organizasyon başına istek limitleri uygular. Entegrasyonunuzu yalnızca değişen kayıtları çekecek, API'nin izin verdiği yerlerde yazma işlemlerini toplu yapacak ve 429 yanıtı geldiğinde zarif biçimde geri çekilecek şekilde tasarlayın. Büyük senkronizasyonlar için, serverless çalışma süresi limitlerine takılabilecek istek işleyicileri yerine arka plan işleri daha uygun bir yerdir.

Token'lara hassas kimlik bilgileri gibi davranın: şifrelenmiş olarak saklayın, tüm Xero kodunu yalnızca sunucuda tutun ve kullanıcı Xero ayarlarından erişimi iptal ettiğinde bağlantı kopmasını düzgün ele alın. Kullanıcılar odaklı bir izin listesini onaylamaya daha yatkın olduğu için yalnızca ihtiyaç duyduğunuz granüler scope'ları talep edin. Son olarak her senkronizasyonu kayıt altına alın ve hatalarda uyarı üretin; böylece sorunlar ay sonunda değil, anında ortaya çıkar.

 

Sonuç

Xero'yu Next.js ile bağlamak, uygulamanıza müşterilerinizin muhasebe verilerine doğrudan ve otomatik erişim kazandırır. Granüler scope'larla bir uygulama kaydederek, OAuth 2.0 akışını route handler'larda kurarak, token'ları serverless ortamda güvenle saklayıp yenileyerek ve webhook'ları doğru şekilde doğrulayarak kullanım büyüdükçe güvenilir kalan bir entegrasyon kurarsınız. İster bir SaaS ürününe faturalama ekliyor ister iç finans süreçlerini otomatikleştiriyor olun, entegrasyonu doğru kurmak şarttır ve hem Xero'yu hem de yazılım mimarisini anlayan deneyimli bir Next.js ekibiyle çalışmak, finansal verilerinizin doğru ve güvende kalmasını sağlar.

xeronext.jsxero entegrasyonumuhasebe entegrasyonuweb geliştirme

Bu yazıyı paylaş

Benzer Yazılar

Benzer yazı bulunamadı.

İlgili Hizmetimiz

Next.js Yazılım Hizmetimiz

Bu konuda profesyonel destek almak ister misiniz?

Hizmeti İncele

İletişim Formu

Bu form üzerinden tarafımıza ulaşabilirsiniz

© 2024-2026 Codefacture Yazılım A.Ş. Tüm Hakları Saklıdır
Hızlı Teklif

Ortalama Yanıt Süresi: 15 Dakika