Coming from v1

v1 is the original NolaPro API: XML responses, HMAC-signed requests, /rest/{controller}/{action}/ URLs. It was written in 2007 and it still runs.

Note

v1 is not being switched off. There is no shutdown date and none is planned. It runs on its own codebase, on its own URL, against the same database. If your integration works, you do not have to touch it.

Move when you want something v2 has: better errors, no request signing, JSON, or an endpoint that only exists in v2.

What changed, and why#

v1v2
FormatXML, <rsp stat="ok"> envelopeJSON
AuthHMAC-SHA1 over concatenated fieldsAuthorization: Bearer
Companyauth[companyid] in every requestA property of the token
URLs/rest/customer/view/123/!/api/v2/customers/123
ErrorsNumeric codesString codes, plus legacy_code
SearchGeneral expression parserNamed filter allow-list
DeletesVariousNone. Cancel actions instead
RulesEnforced in the API's own model layerEnforced by NolaPro's models

The last row is the one that matters most. v1 has its own set of models with their own validation, which means a rule tightened in NolaPro did not automatically apply to the API. v2 calls the application's own model code, so there is one implementation of every rule and it cannot drift.

Mapping your calls#

v1v2
GET /rest/customer/view/123GET /!/api/v2/customers/123
GET /rest/customer/search/companyname/Acme/likeGET /!/api/v2/customers?name=Acme
GET /rest/customer/get_balance/123GET /!/api/v2/customers/123/balance
GET /rest/item/get_item_stats/33/2GET /!/api/v2/items/33/stock?location=2
GET /rest/item/get_item_cost/33/2GET /!/api/v2/items/33/stock?location=2
POST /rest/customer/savePOST /!/api/v2/customers or PATCH /api/v2/customers/{id}
POST /rest/arinvoice/savePOST /!/api/v2/invoices
POST /rest/gltransaction/savePOST /!/api/v2/gltransactions

get_item_stats and get_item_cost collapse into one call because splitting them only ever meant two round trips for one question.

Field names#

v2 uses names that describe what the field is, not what the column has historically been called. Where a name changed, the reference tables show the v1 name underneath.

v2v1Note
namecompanyname
customeridorderbycompanyidOn invoices and orders. The v1 name is a long-standing source of confusion: it is the customer, not an order id.
shiptoidshiptocompanyid

Things that will surprise you#

Money is a string. v1 returned numbers in XML text nodes that most clients coerced to floats. v2 returns "367.6500" and expects the same from you. If you send 367.65 you get 400 invalid_type.

There is no save that does both. v1's save inserted when there was no id and updated when there was. v2 splits them: POST creates, PATCH updates. This was a real source of accidental duplicate records when an id went missing.

Detail rows are a normal array. v1 wanted data[arinvoicedetail][1][field] with 1-based indexes. v2 takes a JSON array called lines.

Search is not general any more. If your integration built expressions and sent them as conditions, there is no v2 equivalent. Tell us which filters you need and they get added by name. This is a real loss of flexibility and a deliberate one: the expression parser could not be made safe.

Company comes from the token. Remove auth[companyid] from your code. If you integrate with several companies, issue one token per company.

Running both at once#

Nothing stops you. They are separate codebases against the same database.

The sane migration is per flow, not big-bang: move your stock reads to v2, leave invoice creation on v1 until you have watched the reads behave for a few weeks, then move the writes.

Because v2 goes through NolaPro's models and v1 does not, a rule tightened in the application applies to your v2 calls and not your v1 calls. In practice that means v2 occasionally rejects something v1 accepts. That is v2 working correctly, and it is worth knowing before you conclude the new API is broken.