You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用PHP SDK编辑已标记为已付款的Xero发票?

Editing a Paid Xero Invoice with the PHP SDK

Hey there, I've tackled this exact scenario with the Xero PHP SDK before—Xero blocks direct edits to invoices marked as Paid by default, so you need to work around their state rules. Here's a step-by-step breakdown of how to make it happen:

Step 1: Fetch the Invoice's Associated Payment(s)

First, you need to find the payment record(s) linked to the paid invoice—removing these is what unlocks the invoice for editing.

use XeroAPI\XeroPHP\Api\AccountingApi;
use XeroAPI\XeroPHP\Configuration;

// Assume you've already set up OAuth2 auth and have your tokens ready
$config = Configuration::getDefaultConfiguration()->setAccessToken('<YOUR_ACCESS_TOKEN>');
$api = new AccountingApi(null, $config);
$tenantId = '<YOUR_TENANT_ID>';
$targetInvoiceId = '<THE_PAID_INVOICE_ID_YOU_WANT_TO_EDIT>';

// Grab the full invoice details, including linked payments
$invoice = $api->getInvoice($tenantId, $targetInvoiceId);
$linkedPayments = $invoice->getPayments();

// Pull the first payment ID (if multiple payments exist, loop through all)
if (!empty($linkedPayments)) {
    $paymentId = $linkedPayments[0]->getPaymentId();
}

Step 2: Delete the Linked Payment to Revert Invoice State

Deleting the payment will flip the invoice's status from Paid back to Authorised—this is the editable state we need.

try {
    $api->deletePayment($tenantId, $paymentId);
    echo "Payment removed successfully; invoice is now editable (Authorised state)";
} catch (Exception $e) {
    echo "Error deleting payment: " . $e->getMessage() . PHP_EOL;
}

Step 3: Make Your Edits to the Invoice

Now that the invoice is back in Authorised status, you can modify any fields you need—like line items, totals, contact details, etc.

// Example edits: update description and total amount
$invoice->setDescription("Updated: Q3 Consulting Services");
$invoice->setTotal(175.00);

try {
    $updatedInvoice = $api->updateInvoice($tenantId, $targetInvoiceId, $invoice);
    echo "Invoice edited successfully!";
} catch (Exception $e) {
    echo "Error updating invoice: " . $e->getMessage() . PHP_EOL;
}

Step 4: Re-apply the Payment to Mark It as Paid Again

Once your edits are done, re-create the payment to set the invoice back to Paid status.

use XeroAPI\XeroPHP\Model\Accounting\Payment;

// Create a new payment object linked to your updated invoice
$payment = new Payment();
$payment->setInvoice($updatedInvoice);
$payment->setAccountCode('090'); // Replace with your actual bank account code
$payment->setAmount(175.00); // Match your updated invoice total
$payment->setDate(new \DateTime());

try {
    $api->createPayment($tenantId, $payment);
    echo "Payment re-applied; invoice is now marked as Paid again";
} catch (Exception $e) {
    echo "Error re-creating payment: " . $e->getMessage() . PHP_EOL;
}

Quick Alternative: Use a Credit Note (If You Don't Want to Delete Payments)

If you don't want to mess with removing existing payment records (e.g., for audit trails), you can create a credit note to offset the original paid invoice, then create a new corrected invoice and mark that as paid instead. This is great for small corrections or when you need to preserve the original transaction history.

Key Notes

  • Make sure your OAuth2 scopes include accounting.transactions and accounting.invoices (read/write permissions are required).
  • If the invoice has multiple linked payments, you'll need to delete all of them to get it back to Authorised status.
  • Always test this workflow in a Xero sandbox first before touching production data!

内容的提问来源于stack exchange,提问作者Niraj Savaliya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 23:42:27