Customers
The companies you invoice. A customer carries terms, credit limit, tax group, and any number of ship-to addresses.
Customers are never removed. DELETE /customers/{id} sets the cancel flag and keeps history intact.
The object#
| Field | Type | Description |
|---|---|---|
| idread-only | integer | NolaPro id. |
| companyname | string(100) | The customer name. Required on create. Not unique, and not a lookup key - use customercode. |
| companyname2 | string(50) | Second name line. |
| customercode | string(30) | Your short code for this customer, and the key the customer reference field resolves against. About a quarter of customers have none. |
| chargecode | string(30) | Charge code shown beside the name in some screens. |
| displaynameread-only | string(255) | Generated by the database from the name and code. Read-only. |
| fullnameread-only | string(255) | Generated by the database. Read-only. |
| address1 | string(100) | Street address. |
| address2 | string(100) | Second address line. |
| city | string(50) | City of the billing address. |
| state | string(20) | State or province. |
| zip | string(15) | Postal code. |
| country | string(20) | Country of the billing address. |
| phone1 | string(20) | Primary phone. |
| email1 | string(255) | Primary email. Where invoices go unless email2sendinvoices says otherwise. |
| email2 | string(255) | Secondary email. |
| website | string(100) | Customer’s website URL. |
| creditlimitmoney | string | Zero means no limit. Stored as a double, not DECIMAL(19,4) - see Conventions on money. |
| invoicetermsid | integer | Terms id. Defaulted from the company setting when omitted on create. |
| invoiceterms | string(30) | Terms code, matched against invoiceterms.verbal. Send this or invoicetermsid, not both unless they agree. |
| currency | string(10) | Currency code for this customer. |
| nocredit | boolean | No credit allowed - this customer pays up front. |
| taxgroupid | integer | Tax group applied to the customer’s sales. |
| taxgroup | string(20) | Tax group code instead of the id. |
| taxexemptid | integer | Tax exemption id, 0 for none. |
| taxexempt | string(32) | Tax exemption name (taxexempt.exemptname) instead of the id. |
| salestaxnum | string(30) | Sales tax registration number. |
| salesmanid | integer | Salesperson id. |
| salesman | string(50) | Salesperson name (salesman.name) instead of the id. |
| salesglacctid | integer | Sales GL account id, 0 to use the company default. |
| salesglacct | string(20) | GL account NUMBER (glaccount.name) instead of the id. |
| groupid | integer | Customer group id. Id only - the table this points at is not identifiable from the column name, so there is no human key to send instead. |
| cancel | boolean | True once cancelled by DELETE. Hidden from lists unless you ask for it. |
| closed | boolean | The relationship has ended. Not the same as cancelled. |
| on_hold | boolean | Trading is suspended, usually for credit. Check this before shipping - an on-hold customer is not cancelled and will otherwise accept orders. |
| on_hold_dateread-only | string | When the hold was applied. |
| default_po | string(30) | Default PO number applied to this customer’s orders. |
| notes | text | Free-text notes. Stored as longtext, so there is no practical length limit. |
| externalid | string(100) | Your own key for this customer. Scoped to your company. |
| lastchangedateread-only | string | Last modification. Drives modifiedsince. |
Endpoints#
List customers.
Filters are a fixed allow-list. Anything not listed here returns 400 naming the parameter.
Requires scope customers:read.
| Name | In | Type | Notes |
|---|---|---|---|
| companyname | query | string | Company name. Partial match, case-insensitive. |
| customercode | query | string | Customer code. Partial match. |
| city | query | string | Billing city. Partial match. |
| state | query | string | Billing state. Partial match. |
| zip | query | string | Billing postal code. Partial match. |
| salesmanid | query | string | Restrict to one salesperson. |
| groupid | query | string | Restrict to one customer group. |
| closed | query | string | true or false. Omitted means both - closed customers still appear, because closed is a status, not a cancellation (D23). |
| on_hold | query | string | true or false. Omitted means both. On hold blocks new orders; it does not hide the customer. |
| cancel | query | string | Defaults to false, which hides cancelled records. Pass true for only cancelled, or any for both. |
| page | query | integer | 1-based. Defaults to 1. |
| perpage | query | integer | Defaults to 50, capped at 250. |
| externalid | query | string | Look up by your own key instead of by id. Unique per company and per system tag. |
| modifiedsince | query | string | RFC 3339 UTC timestamp. Returns only records changed since then, including cancelled ones - so cancel defaults to any rather than false when this is used. The response carries _meta.synced_through; store it and send it back next time. |
| include | query | string | Comma-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. |
| Status | Code | Meaning |
|---|---|---|
| 400 | unknown_parameter | An unknown filter parameter was sent. |
| 401 | unauthorized | Missing, malformed, revoked, or expired token. |
| 403 | forbidden | The token lacks customers:read, or the user has no rights to customers. |
curl \ 'https://acme.nolapro.com/!/api/v2/customers' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/customers", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/customers"); res.EnsureSuccessStatusCode();
{
"data": [
{
"id": 1187,
"companyname": "Summit Retail LLC",
"companyname2": "",
"customercode": "SUMMIT-01",
"chargecode": "",
"displayname": "Summit Retail LLC (SUMMIT-01)",
"fullname": "Summit Retail LLC",
"address1": "900 Industrial Pkwy",
"address2": "",
"city": "Fostoria",
"state": "OH",
"zip": "44830",
"country": "US",
"phone1": "419-435-0404",
"email1": "ap@summitretail.example",
"email2": "",
"website": "",
"creditlimit": "25000.0000",
"invoicetermsid": 112,
"invoiceterms": "Net 30",
"currency": "USD",
"nocredit": false,
"taxgroupid": 4,
"taxgroup": "OH-SEN",
"taxexemptid": 0,
"taxexempt": "Resale",
"salestaxnum": "",
"salesmanid": 3,
"salesman": "Sales Person",
"salesglacctid": 0,
"salesglacct": "4000",
"groupid": 0,
"cancel": false,
"closed": false,
"on_hold": false,
"default_po": "",
"notes": "",
"externalid": "crm-8842",
"lastchangedate": "2026-07-31T14:02:11Z"
}
],
"page": 1,
"perpage": 50,
"total": 214
}
Create a customer.
Requires scope customers:write.
| Name | In | Type | Notes |
|---|---|---|---|
| Field | Type | Description |
|---|---|---|
| companynamerequired | string(100) | The customer name. Required on create. Not unique, and not a lookup key - use customercode. |
| companyname2 | string(50) | Second name line. |
| customercode | string(30) | Your short code for this customer, and the key the customer reference field resolves against. About a quarter of customers have none. |
| address1 | string(100) | Street address. |
| address2 | string(100) | Second address line. |
| city | string(50) | City of the billing address. |
| state | string(20) | State or province. |
| zip | string(15) | Postal code. |
| country | string(20) | Country of the billing address. |
| phone1 | string(20) | Primary phone. |
| email1 | string(255) | Primary email. Where invoices go unless email2sendinvoices says otherwise. |
| creditlimitmoney | string | Zero means no limit. Stored as a double, not DECIMAL(19,4) - see Conventions on money. |
| invoicetermsid | integer | Terms id. Defaulted from the company setting when omitted on create. |
| invoiceterms | string(30) | Terms code, matched against invoiceterms.verbal. Send this or invoicetermsid, not both unless they agree. |
| currency | string(10) | Currency code for this customer. |
| taxgroupid | integer | Tax group applied to the customer’s sales. |
| taxgroup | string(20) | Tax group code instead of the id. |
| salesmanid | integer | Salesperson id. |
| salesman | string(50) | Salesperson name instead of the id. |
| default_po | string(30) | Default PO number applied to this customer’s orders. |
| notes | text | Free-text notes. Stored as longtext, so there is no practical length limit. |
| externalid | string(100) | Your own key for this customer. Scoped to your company. |
| chargecode | string(30) | Charge code shown beside the name in some screens. |
| email2 | string(255) | Secondary email. |
| website | string(100) | Customer’s website URL. |
| nocredit | boolean | No credit allowed - this customer pays up front. |
| taxexemptid | integer | Tax exemption id, 0 for none. |
| taxexempt | string(32) | Tax exemption name (taxexempt.exemptname) instead of the id. |
| salestaxnum | string(30) | Sales tax registration number. |
| salesglacctid | integer | Sales GL account id, 0 to use the company default. |
| salesglacct | string(20) | GL account NUMBER (glaccount.name) instead of the id. |
| groupid | integer | Customer group id. Id only - the table this points at is not identifiable from the column name, so there is no human key to send instead. |
| cancel | boolean | True once cancelled by DELETE. Hidden from lists unless you ask for it. |
| closed | boolean | The relationship has ended. Not the same as cancelled. |
| on_hold | boolean | Trading is suspended, usually for credit. Check this before shipping - an on-hold customer is not cancelled and will otherwise accept orders. |
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A field is missing or the wrong type. |
| 409 | duplicate | A customer with this name already exists in the company. |
| 422 | rule_violation | The values are well-formed but break an accounting rule, for example an unknown terms code. |
curl -X POST \ 'https://acme.nolapro.com/!/api/v2/customers' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '{ "companyname": "Summit Retail LLC", "companyname2": "", "customercode": "SUMMIT-01", "address1": "900 Industrial Pkwy", "address2": "", "city": "Fostoria", "state": "OH", "zip": "44830", "country": "US", "phone1": "419-435-0404", "email1": "ap@summitretail.example", "creditlimit": "25000.0000", "invoicetermsid": 112, "invoiceterms": "Net 30", "currency": "USD", "taxgroupid": 4, "taxgroup": "OH-SEN", "salesmanid": 3, "salesman": "Sales Person", "default_po": "", "notes": "", "externalid": "crm-8842", "chargecode": "", "email2": "", "website": "", "nocredit": false, "taxexemptid": 0, "taxexempt": "Resale", "salestaxnum": "", "salesglacctid": 0, "salesglacct": "4000", "groupid": 0, "cancel": false, "closed": false, "on_hold": false }'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode([ 'companyname' => 'Summit Retail LLC', 'companyname2' => '', 'customercode' => 'SUMMIT-01', 'address1' => '900 Industrial Pkwy', 'address2' => '', 'city' => 'Fostoria', 'state' => 'OH', 'zip' => '44830', 'country' => 'US', 'phone1' => '419-435-0404', 'email1' => 'ap@summitretail.example', 'creditlimit' => '25000.0000', 'invoicetermsid' => 112, 'invoiceterms' => 'Net 30', 'currency' => 'USD', 'taxgroupid' => 4, 'taxgroup' => 'OH-SEN', 'salesmanid' => 3, 'salesman' => 'Sales Person', 'default_po' => '', 'notes' => '', 'externalid' => 'crm-8842', 'chargecode' => '', 'email2' => '', 'website' => '', 'nocredit' => false, 'taxexemptid' => 0, 'taxexempt' => 'Resale', 'salestaxnum' => '', 'salesglacctid' => 0, 'salesglacct' => '4000', 'groupid' => 0, 'cancel' => false, 'closed' => false, 'on_hold' => false, ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.post( "https://acme.nolapro.com/!/api/v2/customers", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json={ "companyname": "Summit Retail LLC", "companyname2": "", "customercode": "SUMMIT-01", "address1": "900 Industrial Pkwy", "address2": "", "city": "Fostoria", "state": "OH", "zip": "44830", "country": "US", "phone1": "419-435-0404", "email1": "ap@summitretail.example", "creditlimit": "25000.0000", "invoicetermsid": 112, "invoiceterms": "Net 30", "currency": "USD", "taxgroupid": 4, "taxgroup": "OH-SEN", "salesmanid": 3, "salesman": "Sales Person", "default_po": "", "notes": "", "externalid": "crm-8842", "chargecode": "", "email2": "", "website": "", "nocredit": False, "taxexemptid": 0, "taxexempt": "Resale", "salestaxnum": "", "salesglacctid": 0, "salesglacct": "4000", "groupid": 0, "cancel": False, "closed": False, "on_hold": False, }, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify({ companyname: "Summit Retail LLC", companyname2: "", customercode: "SUMMIT-01", address1: "900 Industrial Pkwy", address2: "", city: "Fostoria", state: "OH", zip: "44830", country: "US", phone1: "419-435-0404", email1: "ap@summitretail.example", creditlimit: "25000.0000", invoicetermsid: 112, invoiceterms: "Net 30", currency: "USD", taxgroupid: 4, taxgroup: "OH-SEN", salesmanid: 3, salesman: "Sales Person", default_po: "", notes: "", externalid: "crm-8842", chargecode: "", email2: "", website: "", nocredit: false, taxexemptid: 0, taxexempt: "Resale", salestaxnum: "", salesglacctid: 0, salesglacct: "4000", groupid: 0, cancel: false, closed: false, on_hold: false, }), } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var body = new { companyname = "Summit Retail LLC", companyname2 = "", customercode = "SUMMIT-01", address1 = "900 Industrial Pkwy", address2 = "", city = "Fostoria", state = "OH", zip = "44830", country = "US", phone1 = "419-435-0404", email1 = "ap@summitretail.example", creditlimit = "25000.0000", invoicetermsid = 112, invoiceterms = "Net 30", currency = "USD", taxgroupid = 4, taxgroup = "OH-SEN", salesmanid = 3, salesman = "Sales Person", default_po = "", notes = "", externalid = "crm-8842", chargecode = "", email2 = "", website = "", nocredit = false, taxexemptid = 0, taxexempt = "Resale", salestaxnum = "", salesglacctid = 0, salesglacct = "4000", groupid = 0, cancel = false, closed = false, on_hold = false, }; var req = new HttpRequestMessage(HttpMethod.Post, "https://acme.nolapro.com/!/api/v2/customers") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
{
"id": 1187,
"companyname": "Summit Retail LLC",
"companyname2": "",
"customercode": "SUMMIT-01",
"chargecode": "",
"displayname": "Summit Retail LLC (SUMMIT-01)",
"fullname": "Summit Retail LLC",
"address1": "900 Industrial Pkwy",
"address2": "",
"city": "Fostoria",
"state": "OH",
"zip": "44830",
"country": "US",
"phone1": "419-435-0404",
"email1": "ap@summitretail.example",
"email2": "",
"website": "",
"creditlimit": "25000.0000",
"invoicetermsid": 112,
"invoiceterms": "Net 30",
"currency": "USD",
"nocredit": false,
"taxgroupid": 4,
"taxgroup": "OH-SEN",
"taxexemptid": 0,
"taxexempt": "Resale",
"salestaxnum": "",
"salesmanid": 3,
"salesman": "Sales Person",
"salesglacctid": 0,
"salesglacct": "4000",
"groupid": 0,
"cancel": false,
"closed": false,
"on_hold": false,
"default_po": "",
"notes": "",
"externalid": "crm-8842",
"lastchangedate": "2026-07-31T14:02:11Z"
}
Retrieve one customer.
Requires scope customers:read.
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The customer id. |
| include | query | string | Comma-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. |
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No customer with that id in this company. |
curl \ 'https://acme.nolapro.com/!/api/v2/customers/104' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/104'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/customers/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/104', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/customers/104"); res.EnsureSuccessStatusCode();
{
"id": 1187,
"companyname": "Summit Retail LLC",
"companyname2": "",
"customercode": "SUMMIT-01",
"chargecode": "",
"displayname": "Summit Retail LLC (SUMMIT-01)",
"fullname": "Summit Retail LLC",
"address1": "900 Industrial Pkwy",
"address2": "",
"city": "Fostoria",
"state": "OH",
"zip": "44830",
"country": "US",
"phone1": "419-435-0404",
"email1": "ap@summitretail.example",
"email2": "",
"website": "",
"creditlimit": "25000.0000",
"invoicetermsid": 112,
"invoiceterms": "Net 30",
"currency": "USD",
"nocredit": false,
"taxgroupid": 4,
"taxgroup": "OH-SEN",
"taxexemptid": 0,
"taxexempt": "Resale",
"salestaxnum": "",
"salesmanid": 3,
"salesman": "Sales Person",
"salesglacctid": 0,
"salesglacct": "4000",
"groupid": 0,
"cancel": false,
"closed": false,
"on_hold": false,
"default_po": "",
"notes": "",
"externalid": "crm-8842",
"lastchangedate": "2026-07-31T14:02:11Z"
}
Update a customer.
Only the fields you send are changed. There is no PUT - with 168 fields a full replace would blank everything you omitted.
Requires scope customers:write.
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The customer id. |
| Field | Type | Description |
|---|---|---|
| companynamerequired | string(100) | The customer name. Required on create. Not unique, and not a lookup key - use customercode. |
| companyname2 | string(50) | Second name line. |
| customercode | string(30) | Your short code for this customer, and the key the customer reference field resolves against. About a quarter of customers have none. |
| address1 | string(100) | Street address. |
| address2 | string(100) | Second address line. |
| city | string(50) | City of the billing address. |
| state | string(20) | State or province. |
| zip | string(15) | Postal code. |
| country | string(20) | Country of the billing address. |
| phone1 | string(20) | Primary phone. |
| email1 | string(255) | Primary email. Where invoices go unless email2sendinvoices says otherwise. |
| creditlimitmoney | string | Zero means no limit. Stored as a double, not DECIMAL(19,4) - see Conventions on money. |
| invoicetermsid | integer | Terms id. Defaulted from the company setting when omitted on create. |
| invoiceterms | string(30) | Terms code, matched against invoiceterms.verbal. Send this or invoicetermsid, not both unless they agree. |
| currency | string(10) | Currency code for this customer. |
| taxgroupid | integer | Tax group applied to the customer’s sales. |
| taxgroup | string(20) | Tax group code instead of the id. |
| salesmanid | integer | Salesperson id. |
| salesman | string(50) | Salesperson name instead of the id. |
| default_po | string(30) | Default PO number applied to this customer’s orders. |
| notes | text | Free-text notes. Stored as longtext, so there is no practical length limit. |
| externalid | string(100) | Your own key for this customer. Scoped to your company. |
| chargecode | string(30) | Charge code shown beside the name in some screens. |
| email2 | string(255) | Secondary email. |
| website | string(100) | Customer’s website URL. |
| nocredit | boolean | No credit allowed - this customer pays up front. |
| taxexemptid | integer | Tax exemption id, 0 for none. |
| taxexempt | string(32) | Tax exemption name (taxexempt.exemptname) instead of the id. |
| salestaxnum | string(30) | Sales tax registration number. |
| salesglacctid | integer | Sales GL account id, 0 to use the company default. |
| salesglacct | string(20) | GL account NUMBER (glaccount.name) instead of the id. |
| groupid | integer | Customer group id. Id only - the table this points at is not identifiable from the column name, so there is no human key to send instead. |
| cancel | boolean | True once cancelled by DELETE. Hidden from lists unless you ask for it. |
| closed | boolean | The relationship has ended. Not the same as cancelled. |
| on_hold | boolean | Trading is suspended, usually for credit. Check this before shipping - an on-hold customer is not cancelled and will otherwise accept orders. |
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No customer with that id. |
| 409 | stale_record | If-Match did not match. |
curl -X PATCH \ 'https://acme.nolapro.com/!/api/v2/customers/104' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '{ "companyname": "Summit Retail LLC", "companyname2": "", "customercode": "SUMMIT-01", "address1": "900 Industrial Pkwy", "address2": "", "city": "Fostoria", "state": "OH", "zip": "44830", "country": "US", "phone1": "419-435-0404", "email1": "ap@summitretail.example", "creditlimit": "25000.0000", "invoicetermsid": 112, "invoiceterms": "Net 30", "currency": "USD", "taxgroupid": 4, "taxgroup": "OH-SEN", "salesmanid": 3, "salesman": "Sales Person", "default_po": "", "notes": "", "externalid": "crm-8842", "chargecode": "", "email2": "", "website": "", "nocredit": false, "taxexemptid": 0, "taxexempt": "Resale", "salestaxnum": "", "salesglacctid": 0, "salesglacct": "4000", "groupid": 0, "cancel": false, "closed": false, "on_hold": false }'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/104'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_POSTFIELDS => json_encode([ 'companyname' => 'Summit Retail LLC', 'companyname2' => '', 'customercode' => 'SUMMIT-01', 'address1' => '900 Industrial Pkwy', 'address2' => '', 'city' => 'Fostoria', 'state' => 'OH', 'zip' => '44830', 'country' => 'US', 'phone1' => '419-435-0404', 'email1' => 'ap@summitretail.example', 'creditlimit' => '25000.0000', 'invoicetermsid' => 112, 'invoiceterms' => 'Net 30', 'currency' => 'USD', 'taxgroupid' => 4, 'taxgroup' => 'OH-SEN', 'salesmanid' => 3, 'salesman' => 'Sales Person', 'default_po' => '', 'notes' => '', 'externalid' => 'crm-8842', 'chargecode' => '', 'email2' => '', 'website' => '', 'nocredit' => false, 'taxexemptid' => 0, 'taxexempt' => 'Resale', 'salestaxnum' => '', 'salesglacctid' => 0, 'salesglacct' => '4000', 'groupid' => 0, 'cancel' => false, 'closed' => false, 'on_hold' => false, ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.patch( "https://acme.nolapro.com/!/api/v2/customers/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json={ "companyname": "Summit Retail LLC", "companyname2": "", "customercode": "SUMMIT-01", "address1": "900 Industrial Pkwy", "address2": "", "city": "Fostoria", "state": "OH", "zip": "44830", "country": "US", "phone1": "419-435-0404", "email1": "ap@summitretail.example", "creditlimit": "25000.0000", "invoicetermsid": 112, "invoiceterms": "Net 30", "currency": "USD", "taxgroupid": 4, "taxgroup": "OH-SEN", "salesmanid": 3, "salesman": "Sales Person", "default_po": "", "notes": "", "externalid": "crm-8842", "chargecode": "", "email2": "", "website": "", "nocredit": False, "taxexemptid": 0, "taxexempt": "Resale", "salestaxnum": "", "salesglacctid": 0, "salesglacct": "4000", "groupid": 0, "cancel": False, "closed": False, "on_hold": False, }, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/104', { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify({ companyname: "Summit Retail LLC", companyname2: "", customercode: "SUMMIT-01", address1: "900 Industrial Pkwy", address2: "", city: "Fostoria", state: "OH", zip: "44830", country: "US", phone1: "419-435-0404", email1: "ap@summitretail.example", creditlimit: "25000.0000", invoicetermsid: 112, invoiceterms: "Net 30", currency: "USD", taxgroupid: 4, taxgroup: "OH-SEN", salesmanid: 3, salesman: "Sales Person", default_po: "", notes: "", externalid: "crm-8842", chargecode: "", email2: "", website: "", nocredit: false, taxexemptid: 0, taxexempt: "Resale", salestaxnum: "", salesglacctid: 0, salesglacct: "4000", groupid: 0, cancel: false, closed: false, on_hold: false, }), } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var body = new { companyname = "Summit Retail LLC", companyname2 = "", customercode = "SUMMIT-01", address1 = "900 Industrial Pkwy", address2 = "", city = "Fostoria", state = "OH", zip = "44830", country = "US", phone1 = "419-435-0404", email1 = "ap@summitretail.example", creditlimit = "25000.0000", invoicetermsid = 112, invoiceterms = "Net 30", currency = "USD", taxgroupid = 4, taxgroup = "OH-SEN", salesmanid = 3, salesman = "Sales Person", default_po = "", notes = "", externalid = "crm-8842", chargecode = "", email2 = "", website = "", nocredit = false, taxexemptid = 0, taxexempt = "Resale", salestaxnum = "", salesglacctid = 0, salesglacct = "4000", groupid = 0, cancel = false, closed = false, on_hold = false, }; var req = new HttpRequestMessage(HttpMethod.Patch, "https://acme.nolapro.com/!/api/v2/customers/104") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
{
"id": 1187,
"companyname": "Summit Retail LLC",
"companyname2": "",
"customercode": "SUMMIT-01",
"chargecode": "",
"displayname": "Summit Retail LLC (SUMMIT-01)",
"fullname": "Summit Retail LLC",
"address1": "900 Industrial Pkwy",
"address2": "",
"city": "Fostoria",
"state": "OH",
"zip": "44830",
"country": "US",
"phone1": "419-435-0404",
"email1": "ap@summitretail.example",
"email2": "",
"website": "",
"creditlimit": "25000.0000",
"invoicetermsid": 112,
"invoiceterms": "Net 30",
"currency": "USD",
"nocredit": false,
"taxgroupid": 4,
"taxgroup": "OH-SEN",
"taxexemptid": 0,
"taxexempt": "Resale",
"salestaxnum": "",
"salesmanid": 3,
"salesman": "Sales Person",
"salesglacctid": 0,
"salesglacct": "4000",
"groupid": 0,
"cancel": false,
"closed": false,
"on_hold": false,
"default_po": "",
"notes": "",
"externalid": "crm-8842",
"lastchangedate": "2026-07-31T14:02:11Z"
}
Cancel one customer.
Sets the cancel flag through the same path the application uses, so whatever bookkeeping cancelling this record implies happens with it. Nothing is removed. Cancelling an already cancelled customer succeeds.
Requires scope customers:cancel.
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The customer id. |
| Status | Code | Meaning |
|---|---|---|
| 403 | insufficient_scope | The token has customers:write but not customers:cancel. |
| 404 | not_found | No customer with that id in this company. |
| 409 | cannot_cancel | Cannot be cancelled in its current state. The message says why. |
curl -X DELETE \ 'https://acme.nolapro.com/!/api/v2/customers/104' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/104'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'DELETE', ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.delete( "https://acme.nolapro.com/!/api/v2/customers/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/104', { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var req = new HttpRequestMessage(HttpMethod.Delete, "https://acme.nolapro.com/!/api/v2/customers/104"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
{
"id": 1187,
"companyname": "Summit Retail LLC",
"companyname2": "",
"customercode": "SUMMIT-01",
"chargecode": "",
"displayname": "Summit Retail LLC (SUMMIT-01)",
"fullname": "Summit Retail LLC",
"address1": "900 Industrial Pkwy",
"address2": "",
"city": "Fostoria",
"state": "OH",
"zip": "44830",
"country": "US",
"phone1": "419-435-0404",
"email1": "ap@summitretail.example",
"email2": "",
"website": "",
"creditlimit": "25000.0000",
"invoicetermsid": 112,
"invoiceterms": "Net 30",
"currency": "USD",
"nocredit": false,
"taxgroupid": 4,
"taxgroup": "OH-SEN",
"taxexemptid": 0,
"taxexempt": "Resale",
"salestaxnum": "",
"salesmanid": 3,
"salesman": "Sales Person",
"salesglacctid": 0,
"salesglacct": "4000",
"groupid": 0,
"cancel": false,
"closed": false,
"on_hold": false,
"default_po": "",
"notes": "",
"externalid": "crm-8842",
"lastchangedate": "2026-07-31T14:02:11Z"
}
Open balance, per currency.
Replaces v1's customer-balance action. Computed by Customer_model::getAgingSummary() - the AR Aging report's own code, so this and the report cannot disagree.
For the same figure split by age, use /customers/{id}/aging.
Requires scope customers:read.
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The customer id. |
| asofdate | query | string | Defaults to today. |
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No customer with that id. |
curl \ 'https://acme.nolapro.com/!/api/v2/customers/104/balance' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/104/balance'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/customers/104/balance", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/104/balance', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/customers/104/balance"); res.EnsureSuccessStatusCode();
{
"balances": [
{
"currency": "Example currency",
"balance": "125.0000"
}
]
}
Create many.
Always answers 207, one result per item.
Requires scope customers:write.
| Name | In | Type | Notes |
|---|---|---|---|
| Field | Type | Description |
|---|---|---|
| idread-only | integer | NolaPro id. |
| companyname | string(100) | The customer name. Required on create. Not unique, and not a lookup key - use customercode. |
| companyname2 | string(50) | Second name line. |
| customercode | string(30) | Your short code for this customer, and the key the customer reference field resolves against. About a quarter of customers have none. |
| chargecode | string(30) | Charge code shown beside the name in some screens. |
| displaynameread-only | string(255) | Generated by the database from the name and code. Read-only. |
| fullnameread-only | string(255) | Generated by the database. Read-only. |
| address1 | string(100) | Street address. |
| address2 | string(100) | Second address line. |
| city | string(50) | City of the billing address. |
| state | string(20) | State or province. |
| zip | string(15) | Postal code. |
| country | string(20) | Country of the billing address. |
| phone1 | string(20) | Primary phone. |
| email1 | string(255) | Primary email. Where invoices go unless email2sendinvoices says otherwise. |
| email2 | string(255) | Secondary email. |
| website | string(100) | Customer’s website URL. |
| creditlimitmoney | string | Zero means no limit. Stored as a double, not DECIMAL(19,4) - see Conventions on money. |
| invoicetermsid | integer | Terms id. Defaulted from the company setting when omitted on create. |
| invoiceterms | string(30) | Terms code, matched against invoiceterms.verbal. Send this or invoicetermsid, not both unless they agree. |
| currency | string(10) | Currency code for this customer. |
| nocredit | boolean | No credit allowed - this customer pays up front. |
| taxgroupid | integer | Tax group applied to the customer’s sales. |
| taxgroup | string(20) | Tax group code instead of the id. |
| taxexemptid | integer | Tax exemption id, 0 for none. |
| taxexempt | string(32) | Tax exemption name (taxexempt.exemptname) instead of the id. |
| salestaxnum | string(30) | Sales tax registration number. |
| salesmanid | integer | Salesperson id. |
| salesman | string(50) | Salesperson name (salesman.name) instead of the id. |
| salesglacctid | integer | Sales GL account id, 0 to use the company default. |
| salesglacct | string(20) | GL account NUMBER (glaccount.name) instead of the id. |
| groupid | integer | Customer group id. Id only - the table this points at is not identifiable from the column name, so there is no human key to send instead. |
| cancel | boolean | True once cancelled by DELETE. Hidden from lists unless you ask for it. |
| closed | boolean | The relationship has ended. Not the same as cancelled. |
| on_hold | boolean | Trading is suspended, usually for credit. Check this before shipping - an on-hold customer is not cancelled and will otherwise accept orders. |
| on_hold_dateread-only | string | When the hold was applied. |
| default_po | string(30) | Default PO number applied to this customer’s orders. |
| notes | text | Free-text notes. Stored as longtext, so there is no practical length limit. |
| externalid | string(100) | Your own key for this customer. Scoped to your company. |
| lastchangedateread-only | string | Last modification. Drives modifiedsince. |
curl -X POST \ 'https://acme.nolapro.com/!/api/v2/customers/batch' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '[ { "id": 1187, "companyname": "Summit Retail LLC", "companyname2": "", "customercode": "SUMMIT-01", "chargecode": "", "displayname": "Summit Retail LLC (SUMMIT-01)", "fullname": "Summit Retail LLC", "address1": "900 Industrial Pkwy", "address2": "", "city": "Fostoria", "state": "OH", "zip": "44830", "country": "US", "phone1": "419-435-0404", "email1": "ap@summitretail.example", "email2": "", "website": "", "creditlimit": "25000.0000", "invoicetermsid": 112, "invoiceterms": "Net 30", "currency": "USD", "nocredit": false, "taxgroupid": 4, "taxgroup": "OH-SEN", "taxexemptid": 0, "taxexempt": "Resale", "salestaxnum": "", "salesmanid": 3, "salesman": "Sales Person", "salesglacctid": 0, "salesglacct": "4000", "groupid": 0, "cancel": false, "closed": false, "on_hold": false, "default_po": "", "notes": "", "externalid": "crm-8842", "lastchangedate": "2026-07-31T14:02:11Z" } ]'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/batch'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode([ [ 'id' => 1187, 'companyname' => 'Summit Retail LLC', 'companyname2' => '', 'customercode' => 'SUMMIT-01', 'chargecode' => '', 'displayname' => 'Summit Retail LLC (SUMMIT-01)', 'fullname' => 'Summit Retail LLC', 'address1' => '900 Industrial Pkwy', 'address2' => '', 'city' => 'Fostoria', 'state' => 'OH', 'zip' => '44830', 'country' => 'US', 'phone1' => '419-435-0404', 'email1' => 'ap@summitretail.example', 'email2' => '', 'website' => '', 'creditlimit' => '25000.0000', 'invoicetermsid' => 112, 'invoiceterms' => 'Net 30', 'currency' => 'USD', 'nocredit' => false, 'taxgroupid' => 4, 'taxgroup' => 'OH-SEN', 'taxexemptid' => 0, 'taxexempt' => 'Resale', 'salestaxnum' => '', 'salesmanid' => 3, 'salesman' => 'Sales Person', 'salesglacctid' => 0, 'salesglacct' => '4000', 'groupid' => 0, 'cancel' => false, 'closed' => false, 'on_hold' => false, 'default_po' => '', 'notes' => '', 'externalid' => 'crm-8842', 'lastchangedate' => '2026-07-31T14:02:11Z', ], ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.post( "https://acme.nolapro.com/!/api/v2/customers/batch", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json=[ { "id": 1187, "companyname": "Summit Retail LLC", "companyname2": "", "customercode": "SUMMIT-01", "chargecode": "", "displayname": "Summit Retail LLC (SUMMIT-01)", "fullname": "Summit Retail LLC", "address1": "900 Industrial Pkwy", "address2": "", "city": "Fostoria", "state": "OH", "zip": "44830", "country": "US", "phone1": "419-435-0404", "email1": "ap@summitretail.example", "email2": "", "website": "", "creditlimit": "25000.0000", "invoicetermsid": 112, "invoiceterms": "Net 30", "currency": "USD", "nocredit": False, "taxgroupid": 4, "taxgroup": "OH-SEN", "taxexemptid": 0, "taxexempt": "Resale", "salestaxnum": "", "salesmanid": 3, "salesman": "Sales Person", "salesglacctid": 0, "salesglacct": "4000", "groupid": 0, "cancel": False, "closed": False, "on_hold": False, "default_po": "", "notes": "", "externalid": "crm-8842", "lastchangedate": "2026-07-31T14:02:11Z", }, ], ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/batch', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify([ { id: 1187, companyname: "Summit Retail LLC", companyname2: "", customercode: "SUMMIT-01", chargecode: "", displayname: "Summit Retail LLC (SUMMIT-01)", fullname: "Summit Retail LLC", address1: "900 Industrial Pkwy", address2: "", city: "Fostoria", state: "OH", zip: "44830", country: "US", phone1: "419-435-0404", email1: "ap@summitretail.example", email2: "", website: "", creditlimit: "25000.0000", invoicetermsid: 112, invoiceterms: "Net 30", currency: "USD", nocredit: false, taxgroupid: 4, taxgroup: "OH-SEN", taxexemptid: 0, taxexempt: "Resale", salestaxnum: "", salesmanid: 3, salesman: "Sales Person", salesglacctid: 0, salesglacct: "4000", groupid: 0, cancel: false, closed: false, on_hold: false, default_po: "", notes: "", externalid: "crm-8842", lastchangedate: "2026-07-31T14:02:11Z", }, ]), } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var body = new[] { new { id = 1187, companyname = "Summit Retail LLC", companyname2 = "", customercode = "SUMMIT-01", chargecode = "", displayname = "Summit Retail LLC (SUMMIT-01)", fullname = "Summit Retail LLC", address1 = "900 Industrial Pkwy", address2 = "", city = "Fostoria", state = "OH", zip = "44830", country = "US", phone1 = "419-435-0404", email1 = "ap@summitretail.example", email2 = "", website = "", creditlimit = "25000.0000", invoicetermsid = 112, invoiceterms = "Net 30", currency = "USD", nocredit = false, taxgroupid = 4, taxgroup = "OH-SEN", taxexemptid = 0, taxexempt = "Resale", salestaxnum = "", salesmanid = 3, salesman = "Sales Person", salesglacctid = 0, salesglacct = "4000", groupid = 0, cancel = false, closed = false, on_hold = false, default_po = "", notes = "", externalid = "crm-8842", lastchangedate = "2026-07-31T14:02:11Z", }, }; var req = new HttpRequestMessage(HttpMethod.Post, "https://acme.nolapro.com/!/api/v2/customers/batch") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
Open balance split into aging buckets.
Replaces v1's customer-aging action. Computed by Customer_model::getAgingSummary() - the AR Aging report's own code, so this and the report cannot disagree.
Requires scope customers:read.
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The customer id. |
| asofdate | query | string | Defaults to today. |
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No customer with that id. |
curl \ 'https://acme.nolapro.com/!/api/v2/customers/104/aging' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/104/aging'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/customers/104/aging", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/104/aging', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/customers/104/aging"); res.EnsureSuccessStatusCode();
{
"aging": [
{
"buckets": [
{
"label": "Example label",
"fromdays": 1,
"todays": 1,
"amount": "125.0000"
}
]
}
]
}
Customer statement as a PDF
The account statement, covering the last twelve months.
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.
Requires scope customers:read.
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The customer id. |
curl \ 'https://acme.nolapro.com/!/api/v2/customers/104/statement' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/104/statement'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/customers/104/statement", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/104/statement', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/customers/104/statement"); res.EnsureSuccessStatusCode();
Customer invoice status as a PDF
Where each of the customer’s orders and invoices currently stands.
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.
Requires scope customers:read.
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The customer id. |
curl \ 'https://acme.nolapro.com/!/api/v2/customers/104/invoicestatus' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/customers/104/invoicestatus'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.get( "https://acme.nolapro.com/!/api/v2/customers/104/invoicestatus", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/customers/104/invoicestatus', { method: 'GET', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, } ); const data = await res.json();
using System.Net.Http.Json; var token = Environment.GetEnvironmentVariable("NP_TOKEN"); using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); var res = await http.GetAsync( "https://acme.nolapro.com/!/api/v2/customers/104/invoicestatus"); res.EnsureSuccessStatusCode();