Payments

Payments applied to an invoice.

The object#

FieldTypeDescription
idread-onlyintegerNolaPro id.
invoiceidintegerInvoiceid. Id only.
invoicestring(30)The invoicenumber of the referenced invoices, instead of the id. Send this or invoiceid, not both unless they agree.
amountmoneystring(4dp)Stored as decimal(19,4).
voucheridintegerVoucherid. Id only.
voucherstring(50)The voucher of the referenced gltransactions, instead of the id. Send this or voucherid, not both unless they agree.
datereceivedstringDate the payment was received - the accounting date it posts under.
paymethintegerPayment method code: 1 = cash, 2 = check (the POS writes 2 for credit card), 3 = credit card, 4 = ACH/EFT, 5 = POS card terminal, 99 = write-off; 0 = on account or unset.
interestinteger1 when the payment pays finance-charge interest rather than invoice principal.
cancelbooleanCancelled. Always a boolean on the wire, whatever integer width the column uses (D23).
cancel_useridread-onlyintegerUser who voided the payment.
cancel_userstring(50)The name of the referenced genusers, instead of the id. Send this or cancel_userid, not both unless they agree.
checkidstring(100)Check number or payment reference the customer paid with.
bankdepositidintegerBankdepositid. Id only.
bankstatement_enddateread-onlystringEnd date of the bank statement the payment was reconciled under. Maintained by bank reconciliation, so it cannot be written through the API.
old_idread-onlystring(255)Payment id in the system this record was imported from.
refund_paymethintegerPayment method used for the refund, when the payment is a refund.
cctransactionidintegerCctransactionid. Id only.
currencystring(10)Currency the payment was received in.
returnedinteger1 when the payment was returned by the bank (NSF/bounced).
feeinvoiceidintegerFeeinvoiceid. Id only.
feeinvoicestring(30)The invoicenumber of the referenced invoices, instead of the id. Send this or feeinvoiceid, not both unless they agree.
feeapbillidintegerFeeapbillid. Id only.
bankfee_amountmoneystring(4dp)Stored as decimal(19,4).
bankfee_glidintegerGL account a bank fee taken out of the payment posts to.
bankfee_glstring(20)The name of the referenced glaccounts, instead of the id. Send this or bankfee_glid, not both unless they agree.
rnumstring(30)Reference number recorded with the payment (remittance or voucher reference).
tenderedmoneystring(4dp)Stored as decimal(19,4).
transidstring(32)Gateway transaction id, for card and online payments.
orderdepositidintegerOrderdepositid. Id only.
ccterminalidintegerCcterminalid. Id only.
costcodeidintegerCost code.
costcodestring(20)Code for the referenced costcode, instead of the id.
inventorylocationidintegerInventorylocationid. Id only.
inventorylocationstring(20)The locationcode of the referenced inventorylocations, instead of the id. Send this or inventorylocationid, not both unless they agree.
isb2bpaymentbooleanTrue when the customer paid through the B2B portal.
isb2bpaymentfeebooleanTrue when the record is the convenience fee charged on a B2B portal payment.
jointcheckbooleanTrue when the payment is a joint check (AR joint checks feature).
bankstatement_cleardateread-onlystringDate the payment cleared the bank. Maintained by bank reconciliation, so it cannot be written through the API.
extuseridintegerExtuserid. Id only.
ispaymentonaccountbooleanTrue when the payment is on account rather than applied to a specific invoice.
writeoffreasonidintegerWrite-off reason (writeoffreason id) when the payment is a write-off (paymeth 99).
creditfromarinvoicepaymentdetailidintegerCreditfromarinvoicepaymentdetailid. Id only.
credittoarinvoicepaymentdetailidintegerCredittoarinvoicepaymentdetailid. Id only.
entrydatestringWhen the record was created.
customeridintegerReference to customers, by id. Write either this or customer.
customerstring(30)Code for the referenced customer, instead of the id.
datereceivedandvoucheridread-onlyintegerSTORED GENERATED in the database. Read-only - MySQL computes it, and a value sent here is silently discarded.
pendingarachbankrecdatereceivedread-onlystringSTORED GENERATED in the database. Read-only - MySQL computes it, and a value sent here is silently discarded.
creditorderdepositidintegerCreditorderdepositid. Id only.
checkaccountidintegerChecking account the payment was deposited to.
checkaccountstring(30)The name of the referenced checkaccounts, instead of the id. Send this or checkaccountid, not both unless they agree.
externalidstring(100)Your own key. Scoped to your company.

Endpoints#

POST/payments/batch 207400422

Create many.

Requires scope payments:write.

Parameters
NameInTypeNotes
Idempotency-KeyheaderstringMakes the write safely retryable. Any unique string per logical operation; a UUID is fine. The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing. The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours.
Body array
FieldTypeDescription
invoiceidrequiredintegerThe POSTED invoice being paid.
amountrequiredmoneystringHow much was received. Decimal STRING, not a JSON number.
datestringDate received. Defaults to today.
methodintegerPayment method id.
referencestring(100)Cheque number or transaction reference.
externalidstring(100)Your own identifier for this record. Stored verbatim and returned on reads; GET /<resource>?externalid=... finds it again.
When it fails
StatusCodeMeaning
400invalid_requestThe request was malformed.
422period_closedThe GL period containing the date is closed.
422rule_violationNolaPro refused the document. message carries its reason.
422unknown_valueA reference did not resolve in this company.
curl -X POST \
  'https://acme.nolapro.com/!/api/v2/payments/batch' \
  -H 'Authorization: Bearer $NP_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: your-unique-key' \
  -d '[
    {
        "invoiceid": 104,
        "amount": "125.0000",
        "date": "2026-08-02",
        "externalid": "crm-8842"
    }
]'
Response 207
{
    "results": [
        {
            "index": 1,
            "status": 1
        }
    ]
}
GET/payments 200403

List payments.

Requires scope payments:read.

Parameters
NameInTypeNotes
customeridquerystringRestrict to one customerid.
inventorylocationidquerystringRestrict to one inventorylocationid.
invoiceidquerystringRestrict to one invoiceid.
cancelquerystringDefaults to false. Pass true or any.
externalidquerystringExact match on your own key.
includequerystringComma-separated extras to embed. Only custom_fields is available: the extra fields this install has defined on the record. Off by default, and an unrecognised value is refused rather than ignored. See Conventions.
bankdepositidqueryintegerRestrict to payments on one bank deposit. Pass 0 for the ones not yet banked.
When it fails
StatusCodeMeaning
403insufficient_scopeToken lacks read scope.
curl \
  'https://acme.nolapro.com/!/api/v2/payments' \
  -H 'Authorization: Bearer $NP_TOKEN'
POST/payments 201400422

Create.

Requires scope payments:write.

Parameters
NameInTypeNotes
Idempotency-KeyheaderstringMakes the write safely retryable. Any unique string per logical operation; a UUID is fine. The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing. The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours.
Body
FieldTypeDescription
invoiceidrequiredintegerThe POSTED invoice being paid.
amountrequiredmoneystringHow much was received. Decimal STRING, not a JSON number.
datestringDate received. Defaults to today.
methodintegerPayment method id.
referencestring(100)Cheque number or transaction reference.
externalidstring(100)Your own identifier for this record. Stored verbatim and returned on reads; GET /<resource>?externalid=... finds it again.
When it fails
StatusCodeMeaning
400invalid_requestA required field was missing.
422period_closedThe GL period containing the date is closed.
422rule_violationNolaPro refused the document. message carries its reason.
422unknown_valueA reference did not resolve in this company.
curl -X POST \
  'https://acme.nolapro.com/!/api/v2/payments' \
  -H 'Authorization: Bearer $NP_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: your-unique-key' \
  -d '{
    "invoiceid": 104,
    "amount": "125.0000",
    "date": "2026-08-02",
    "externalid": "crm-8842"
}'
Response 201
{
    "invoiceid": 104,
    "amount": "125.0000",
    "voucherid": 104,
    "invoicepaid": "Example invoicepaid"
}
GET/payments/{id} 200404

Retrieve one record.

Requires scope payments:read.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
includequerystringComma-separated extras to embed. Only custom_fields is available: the extra fields this install has defined on the record. Off by default, and an unrecognised value is refused rather than ignored. See Conventions.
When it fails
StatusCodeMeaning
404not_foundNo record with that id.
curl \
  'https://acme.nolapro.com/!/api/v2/payments/104' \
  -H 'Authorization: Bearer $NP_TOKEN'
Response 200
{
    "invoiceid": 104,
    "invoice": "Example invoice",
    "amount": "125.0000",
    "voucherid": 104,
    "voucher": "Example voucher",
    "datereceived": "2026-08-01"
}
PATCH/payments/{id} 200400404409422

Update.

Requires scope payments:write.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
Idempotency-KeyheaderstringMakes the write safely retryable. Any unique string per logical operation; a UUID is fine. The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing. The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours.
Body
FieldTypeDescription
referencestring(100)Cheque number or transaction reference.
methodintegerPayment method id.
externalidstring(100)Your own identifier for this record.
When it fails
StatusCodeMeaning
400invalid_requestThe request was malformed.
404not_foundNo such record, or it belongs to another company.
409stale_recordIf-Match did not match; someone else changed it first.
422rule_violationNolaPro refused the change. message carries its reason.
curl -X PATCH \
  'https://acme.nolapro.com/!/api/v2/payments/104' \
  -H 'Authorization: Bearer $NP_TOKEN' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: your-unique-key' \
  -d '{
    "reference": "Example reference",
    "method": 1
}'
DELETE/payments/{id} 200400409422

Cancel.

Requires scope payments:cancel.

Parameters
NameInTypeNotes
idrequiredpathintegerThe record id.
Idempotency-KeyheaderstringMakes the write safely retryable. Any unique string per logical operation; a UUID is fine. The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing. The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours.
When it fails
StatusCodeMeaning
400invalid_requestThe request was malformed.
409cannot_cancelSomething already depends on this document - a payment, a shipment, an invoice.
422period_closedThe current GL period is closed, so a reversal has nowhere to post.
422unknown_valueNo such record in this company.
curl -X DELETE \
  'https://acme.nolapro.com/!/api/v2/payments/104' \
  -H 'Authorization: Bearer $NP_TOKEN'
GET/payments/{id}/receipt 200409

Payment receipt as a PDF

The receipt for a payment, covering every invoice its voucher settled. Answers application/pdf, not JSON. Because the body is binary it cannot be carried inside a /batch results array; asking for it there returns 415 not_batchable. A payment with no voucher is refused with 409 not_posted.

Requires scope payments:read.

Parameters
NameInTypeNotes
idrequiredpathintegerThe invoice id.
When it fails
StatusCodeMeaning
409The invoice is still a draft.
curl \
  'https://acme.nolapro.com/!/api/v2/payments/104/receipt' \
  -H 'Authorization: Bearer $NP_TOKEN'
GET/payments/{id}/attachments 200404

List files attached to a payment.

The attachments on this payment, newest first. Accepted filedefinitionid values: 42 (default 42). Metadata only - each file's bytes are at GET /attachments/{id}/content.

Requires scope payments:read.

Parameters
NameInTypeNotes
idrequiredpathintegerThe payment id.
filedefinitionidqueryintegerOnly files in this list. Accepted filedefinitionid values: 42 (default 42).
filecategoryidqueryintegerOnly files filed under this category.
filenamequerystringPartial match on the file name, case insensitive.
When it fails
StatusCodeMeaning
404not_foundNo payment with that id in this company.
curl \
  'https://acme.nolapro.com/!/api/v2/payments/104/attachments' \
  -H 'Authorization: Bearer $NP_TOKEN'
POST/payments/{id}/attachments 201400404409413415422

Attach a file to a payment.

multipart/form-data with one file part; see the AttachmentUpload schema for the other parts. Accepted filedefinitionid values: 42 (default 42). Answers 201 with the attachment's metadata and Location: /attachments/{id}. Check _meta.warnings for datatype_truncated and stored_under_parent_company.

Requires scope payments:write.

Parameters
NameInTypeNotes
idrequiredpathintegerThe payment id.
Idempotency-KeyheaderstringMakes the write safely retryable. Any unique string per logical operation; a UUID is fine. The failure this prevents is specific: the request succeeds, the response is lost to a timeout, you retry, and the customer is billed twice. With a key, the retry returns the original response - same status, same body, same id - and creates nothing. The body is part of the key's identity. Reusing a key with a different body is a bug on your side, not a retry, and answers 409 idempotency_replay rather than silently handing back the old response. Keys are remembered for 24 hours.
Body multipart/form-data
FieldTypeDescription
filerequiredstringThe file. Exactly one part named file; a second one, or file[], is 400 invalid_request so an idempotent retry can never half-succeed. Empty is refused. Over the cap (the smaller of APIV2_MAX_UPLOAD_BYTES, 64 MB by default, and PHP's upload_max_filesize / post_max_size) is 413 payload_too_large naming the limit that applied.
filenamestring(255)Overrides the part's file name.
notestextFree text shown beside the file.
filedefinitionidintegerOnly when the parent accepts more than one list. Anything the parent does not accept is 422 unknown_value naming the accepted ids.
filecategoryidintegerCategory by id.
filecategorystring(255)Category by name. Sent with filecategoryid and disagreeing is 422 conflicting_reference.
When it fails
StatusCodeMeaning
400unknown_parameterA form field that is not on the AttachmentUpload schema.
400invalid_typefiledefinitionid or filecategoryid that is not an integer.
404not_foundNo payment with that id in this company.
409upload_limit_reachedThis file list allows a fixed number of files on a payment and it is full. Remove one first.
413payload_too_largeThe file is over the cap. The body names the limit that applied.
415multipart_requiredThe body was not multipart/form-data.
422unknown_valuefiledefinitionid is not one this payment accepts, or the category does not exist in this company.
curl -X POST \
  'https://acme.nolapro.com/!/api/v2/payments/104/attachments' \
  -H 'Authorization: Bearer $NP_TOKEN' \
  -H 'Idempotency-Key: your-unique-key' \
  -F 'file=@grant-letter-signed.pdf' \
  -F 'filename=grant-letter-signed.pdf' \
  -F 'notes=Signed copy received 21 Sep' \
  -F 'filedefinitionid=8' \
  -F 'filecategory=Receipts'