Skip to main content

Purchases

Purchases (sometimes called bills or vendor invoices) record what your organization owes to suppliers. Each purchase stores the supplier contact, currency, due date, line-level expense accounts, VAT, and payment status. This guide covers the public GraphQL operations you can call to import purchase data, sync statuses, or issue payments from your own back office tools.

Authenticate with an API secret or OAuth-issued secret as described in the Authentication guide, then include the organization slug on every query or mutation.

Core objects​

Purchase​

FieldTypeDescription
idID!Stable identifier for follow-up mutations.
numberInt!Auto-incremented sequence, unique per organization.
dateDate!Posting date used for ledgers and reporting.
dueDateDate!Required for credit purchases; equals date for cash purchases.
statusPurchaseStatus!draft, active, paid, partial, or voided.
paymentStatusStringDerived indicator in the UI (unpaid, overdue, etc.).
total / subtotal / vatStringDecimal strings in the organization's base currency.
remainderStringOutstanding balance (negative numbers represent amounts still owed).
currency / exchangeRateStringOriginal document currency and applied exchange rate.
originalTotalStringTotal expressed in the original currency.
contactContactSupplier info (name, email, address).
lines[PurchaseLine!]!Ledger distribution for the expense and VAT.
journalEntries[JournalEntry!]Ledger postings created for the purchase and any payments.

PurchaseLine​

FieldTypeDescription
idID!Line identifier.
descriptionString!Human-readable text shown on the document.
costString!Decimal cost in purchase currency.
accountIdID!Expense, asset, or liability account to debit.
vatIdIDOptional VAT code applied to the line.

Status and type rules​

  • PurchaseType values are cash (immediately paid from a bank or cash account) and credit (posted to accounts payable).
  • New purchases can only be created as draft or active. Drafts can be edited; active purchases represent posted payables.
  • Voiding a purchase sets status to voided and voids all related journal entries.

Query purchases​

Fetch a single purchase​

query Purchase($id: ID!) {
purchase(purchaseID: $id) {
id
number
status
currency
total
remainder
contact {
id
name
email
}
lines {
id
description
cost
account {
id
name
code
}
}
journalEntries {
id
number
date
}
}
}

Use this to display all metadata for reconciliation or auditing tools.

List purchases with filters​

query Purchases($slug: Slug!, $filter: JSONObject) {
organization(slug: $slug) {
purchases(
limit: 50
orderBy: { field: "due_date", order: ASC }
filter: $filter
) {
count
entries {
id
number
date
dueDate
status
contact {
name
}
total
remainder
}
}
}
}

Filters accept the standard operators (equalTo, notEqualTo, lessThan, greaterThanOrEqualTo, in, plus and/or). Common fields include status, contactId, due_date, and currency. The orderBy object supports any column on the underlying purchase (for example created_at, date, or due_date). Max page size is 1,000 entries.

Create and update purchases​

Create​

mutation CreatePurchase($input: CreatePurchaseInput!) {
createPurchase(input: $input) {
id
number
status
total
remainder
}
}

CreatePurchaseInput fields:

FieldRequiredNotes
slug✅Organization identifier tied to the API secret.
type✅cash requires accountId; credit posts to accounts payable.
date✅Posting date; dueDate defaults to this when type is cash.
dueDate⚠️Required for credit purchases.
contactId⚠️Optional but recommended for tracking suppliers.
accountId⚠️Expense account for cash purchases (the credit side of the journal entry).
currency / exchangeRate⚠️Default to the org base currency when omitted. Provide both for multi-currency docs.
status✅Must be draft or active.
lines✅At least one PurchaseLineInput with cost, description, and accountId.
docs⚠️Array of existing document IDs (from createDoc) to attach receipts.

Update​

mutation UpdatePurchase($input: UpdatePurchaseInput!) {
updatePurchase(input: $input) {
id
status
dueDate
lines {
id
description
cost
}
}
}

Updates are only allowed while status = draft. To revise a posted document, void it and re-create it. When sending new lines, the mutation replaces every existing line item, so always send the complete set.

Pay purchases​

Use payPurchase when you record an actual bank disbursement or cash payment.

mutation PayPurchase($input: PayPurchaseInput!) {
payPurchase(input: $input) {
id
number
remainder
journalEntries {
id
date
}
}
}

PayPurchaseInput fields:

FieldRequiredNotes
purchaseId✅Target purchase ID.
amount✅Decimal string (positive numbers reduce the payable). Partial payments are supported.
accountId⚠️Credit account used for the payment (cash or bank). Defaults to the organization's defaultBankAccount if omitted.
date⚠️Defaults to the current date.
exchangeRateOptionalPurchase currency to organization currency. Omit it when they differ and Naqood uses the rate for date (or today). Pass a value to use that rate instead.
transactionCurrency / transactionAmount / transactionExchangeRateOptionalBank side of the payment when it is not in the purchase currency. transactionExchangeRate is required when the bank currency differs from both the purchase currency and the organization currency.
comment⚠️Optional narration shown on the journal entry.

Naqood automatically posts the debit to the selected cash/bank account and the credit to accounts payable. When you pay in another currency, the system routes any gain or loss to the configured exchange-rate accounts.

Void purchases​

mutation DeletePurchase($id: ID!) {
deletePurchase(purchaseId: $id)
}

deletePurchase voids the purchase and every associated journal entry. Only non-voided purchases can be voided. Use this for mistakes rather than archival; the purchase ID remains but its status becomes voided.