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 or asset 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
slugOrganization identifier tied to the API secret.
typecash requires accountId; credit posts to accounts payable.
datePosting 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.
statusMust be draft or active.
linesAt 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
purchaseIdTarget purchase ID.
amountDecimal 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.
currency / exchangeRate⚠️Provide when paying in a currency different from the purchase currency. Exchange gains/losses are posted automatically.
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.