AP bill lines
Lines on a vendor bill. Normally sent nested inside the bill.
The object#
| Field | Type | Description |
|---|---|---|
| idread-only | integer | NolaPro id. |
| apbillid | integer | Apbillid. Id only. |
| amountmoney | string(4dp) | Stored as decimal(19,4). |
| glaccountid | integer | Reference to glaccounts, by id. Write either this or glaccount. |
| glaccount | string(20) | Code for the referenced glaccount, instead of the id. |
| invreceiveid | integer | Invreceiveid. Id only. |
| jobid | integer | Jobid. Id only. |
| costcodeid | integer | Cost code. |
| costcode | string(20) | Code for the referenced costcode, instead of the id. |
| glcategoryid | integer | Glcategoryid. Id only. |
| glcategory | string(20) | The code of the referenced glcategories, instead of the id. Send this or glcategoryid, not both unless they agree. |
| description | string(100) | What the expense line covers. |
| isretainer | integer | 1 when the line is withheld retainage. |
| curratenumber | string(10dp) | Numeric string, 10 decimal places. Not money - do not apply currency rounding. |
| externalid | string(100) | Your own key. Scoped to your company. |
Endpoints#
POST/apbilllines/batch
207400409422
Create many.
Requires scope bills:write.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
Body array
| Field | Type | Description |
|---|---|---|
| apbillidrequired | integer | The UNPOSTED bill to code. A posted bill is refused. |
| glaccountid | integer | Account id. Or send glaccount by name. |
| glaccount | string(60) | Account name, matched exactly. |
| amountrequiredmoney | string | How much codes to this account. Cannot take the distribution past the bill total. Decimal STRING, not a JSON number. |
| jobid | integer | Job to cost this to. |
| costcodeid | integer | Cost code. |
| externalid | string(100) | Your own identifier for this record. Stored verbatim and returned on reads; GET /<resource>?externalid=... finds it again. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The request was malformed. |
| 409 | apbill_already_posted | The bill already carries a voucherid. |
| 422 | distribution_exceeds_total | The line would code more than the bill is for. |
| 422 | rule_violation | NolaPro refused the document. message carries its reason. |
| 422 | unknown_value | A reference did not resolve in this company. |
curl -X POST \ 'https://acme.nolapro.com/!/api/v2/apbilllines/batch' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '[ { "apbillid": 104, "amount": "125.0000", "externalid": "crm-8842" } ]'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/apbilllines/batch'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode([ [ 'apbillid' => 104, 'amount' => '125.0000', 'externalid' => 'crm-8842', ], ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.post( "https://acme.nolapro.com/!/api/v2/apbilllines/batch", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json=[ { "apbillid": 104, "amount": "125.0000", "externalid": "crm-8842", }, ], ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/apbilllines/batch', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify([ { apbillid: 104, amount: "125.0000", externalid: "crm-8842", }, ]), } ); 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 { apbillid = 104, amount = "125.0000", externalid = "crm-8842", }, }; var req = new HttpRequestMessage(HttpMethod.Post, "https://acme.nolapro.com/!/api/v2/apbilllines/batch") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
Response 207
{
"results": [
{
"index": 1,
"status": 1
}
]
}
GET/apbilllines
200403
List ap bill lines.
Requires scope bills:read.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| jobid | query | string | Restrict to one jobid. |
| description | query | string | description. Partial match, case-insensitive. |
| externalid | query | string | Exact match on your own key. |
| 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. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 403 | insufficient_scope | Token lacks read scope. |
curl \ 'https://acme.nolapro.com/!/api/v2/apbilllines' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/apbilllines'); 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/apbilllines", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/apbilllines', { 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/apbilllines"); res.EnsureSuccessStatusCode();
POST/apbilllines
201400409422
Create.
Requires scope bills:write.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
Body
| Field | Type | Description |
|---|---|---|
| apbillidrequired | integer | The UNPOSTED bill to code. A posted bill is refused. |
| glaccountid | integer | Account id. Or send glaccount by name. |
| glaccount | string(60) | Account name, matched exactly. |
| amountrequiredmoney | string | How much codes to this account. Cannot take the distribution past the bill total. Decimal STRING, not a JSON number. |
| jobid | integer | Job to cost this to. |
| costcodeid | integer | Cost code. |
| externalid | string(100) | Your own identifier for this record. Stored verbatim and returned on reads; GET /<resource>?externalid=... finds it again. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A required field was missing. |
| 409 | apbill_already_posted | The bill already carries a voucherid. |
| 422 | distribution_exceeds_total | The line would code more than the bill is for. |
| 422 | rule_violation | NolaPro refused the document. message carries its reason. |
| 422 | unknown_value | A reference did not resolve in this company. |
curl -X POST \ 'https://acme.nolapro.com/!/api/v2/apbilllines' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '{ "apbillid": 104, "amount": "125.0000", "externalid": "crm-8842" }'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/apbilllines'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode([ 'apbillid' => 104, 'amount' => '125.0000', 'externalid' => 'crm-8842', ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.post( "https://acme.nolapro.com/!/api/v2/apbilllines", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json={ "apbillid": 104, "amount": "125.0000", "externalid": "crm-8842", }, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/apbilllines', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify({ apbillid: 104, amount: "125.0000", externalid: "crm-8842", }), } ); 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 { apbillid = 104, amount = "125.0000", externalid = "crm-8842", }; var req = new HttpRequestMessage(HttpMethod.Post, "https://acme.nolapro.com/!/api/v2/apbilllines") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
Response 201
{
"apbillid": 104,
"glaccountid": 104,
"amount": "125.0000",
"billtotal": "125.0000",
"distributed": "125.0000",
"undistributed": "125.0000"
}
GET/apbilllines/{id}
200404
Retrieve one record.
Requires scope bills:read.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The record 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. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 404 | not_found | No record with that id. |
curl \ 'https://acme.nolapro.com/!/api/v2/apbilllines/104' \ -H 'Authorization: Bearer $NP_TOKEN'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/apbilllines/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/apbilllines/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/apbilllines/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/apbilllines/104"); res.EnsureSuccessStatusCode();
Response 200
{
"apbillid": 104,
"amount": "125.0000",
"glaccountid": 104,
"glaccount": "Example glaccount",
"invreceiveid": 104,
"jobid": 104
}
PATCH/apbilllines/{id}
200400404409422
Update.
Requires scope bills:write.
Parameters
| Name | In | Type | Notes |
|---|---|---|---|
| idrequired | path | integer | The record id. |
Body
| Field | Type | Description |
|---|---|---|
| amountmoney | string | How much codes to this account. Decimal STRING. |
| glaccountid | integer | Account this line codes to. |
| jobid | integer | Job to cost this to. |
| costcodeid | integer | Cost code. |
| externalid | string(100) | Your own identifier for this record. |
When it fails
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | The request was malformed. |
| 404 | not_found | No such record, or it belongs to another company. |
| 409 | apbill_already_posted | The bill already carries a voucherid. |
| 409 | stale_record | If-Match did not match; someone else changed it first. |
| 422 | distribution_exceeds_total | The change would code more than the bill is for. |
| 422 | rule_violation | NolaPro refused the change. message carries its reason. |
curl -X PATCH \ 'https://acme.nolapro.com/!/api/v2/apbilllines/104' \ -H 'Authorization: Bearer $NP_TOKEN' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: your-unique-key' \ -d '{ "amount": "12.5000" }'
$ch = curl_init('https://acme.nolapro.com/!/api/v2/apbilllines/104'); curl_setopt_array($ch, [ CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('NP_TOKEN')], CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_POSTFIELDS => json_encode([ 'amount' => '12.5000', ]), ]); $res = json_decode(curl_exec($ch), true);
import os, requests r = requests.patch( "https://acme.nolapro.com/!/api/v2/apbilllines/104", headers={"Authorization": f"Bearer {os.environ['NP_TOKEN']}"}, json={ "amount": "12.5000", }, ) r.raise_for_status()
const res = await fetch( 'https://acme.nolapro.com/!/api/v2/apbilllines/104', { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.NP_TOKEN}` }, body: JSON.stringify({ amount: "12.5000", }), } ); 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 { amount = "12.5000", }; var req = new HttpRequestMessage(HttpMethod.Patch, "https://acme.nolapro.com/!/api/v2/apbilllines/104") { Content = JsonContent.Create(body), }; req.Headers.Add("Idempotency-Key", "your-unique-key"); var res = await http.SendAsync(req); res.EnsureSuccessStatusCode();
GL accounts →
name holds the account number and description holds the label. That is backwards from most expectations and it is the single most important thing to know about this resource. Scoped per company, on the companyid column.GL account types →
The account types behind
glaccounts.accounttypeid - asset, liability, income and so on. Fixed by double-entry accounting rather than by configuration, so read-only.