Consuming the REST API

Consuming the REST API



Conventions


The Jiwa REST API is based on the Data Transfer Object (DTO) pattern.

Every request accepts a DTO and almost every response is a DTO.  You can, in some cases encode the request DTO as URL parameters instead, such as authentication and query requests.

The DTO classes can be obtained from the following routes:

Language

Route

Language

Route

C#

/types/csharp

VB.NET

/types/vbnet

F#

/types/fsharp

Typescript

/types/typescript

Java

/types/java

Kotlin

/types/kotlin

Swift

/types/swift

Additionally, you can use your tool of choice to generate the DTO's from the Open API specification document located at /openapi

Content Negotiation

By default the Jiwa REST API is configured to accept json DTO's and return json DTO's. This default content type can be changed in the configuration, or the client can override the content type. If using the ServiceStack client, then there is no concern of the content type as it is automatically negotiated.

In addition to using the standard Accept HTTP Header to retrieve the response a different format, you can also request an alternative Content-Type by appending ?format=ext to the query string, e.g:

  •  

    • /Debtors/{DebtorID}?format=json

    • /Debtors/{DebtorID}?format=xml

    • /Debtors/{DebtorID}?format=csv

Or by appending the format .ext to the end of the route, e.g:

  •  

    • /Debtors/{DebtorID}.json

    • /Debtors/{DebtorID}.xml

    • /Debtors/{DebtorID}.csv

Verbs

  • GET operations are used to retrieve data

  • POST operations are used to create data

  • PATCH operations are used to update existing data

  • DELETE operations are used to delete existing data

HTTP Response Codes

The response code returned will vary based on the type of operation and the result of the request.

200 OK

Will be returned for most GET operations - unless there was nothing to return, then a 204 No Content will be returned

201 Created

Will be returned for successful POST operations

204 No Content

Will be returned for successful DELETE operations

401 Not Authenticated

Will be returned if the operation requires the user to be authenticated, and they are not - or if they are authenticating and it failed due to bad credentials.

403 Forbidden

Will be returned if the user is authenticated, but do not have permission to perform the operation. See Setting Route Permissions for information on setting route permissions.

404 Not Found

Will be returned if the route is invalid, or the resource requested does not exist.

409 Conflict

Will be returned if the Jiwa business logic determines you can't perform the operation. This may occur with DELETE operations if the record cannot be deleted because it is referenced elsewhere (e.g: You can't delete a product because it is used on a sales order).

You may also get a 409 response due to a concurrency conflict.  Jiwa uses optimistic concurrency control, and if the record changes because of another users or processes actions between a read and save, then this error will be returned.

Routing

ServiceStack clients don't care about routes

Note that if using a ServiceStack client you do not need to be concerned with routes. The route is worked out by the client based on the type of the DTO being sent.

The convention used for route structure is to use a plural noun of the resource followed by the primary key (usually an ID) of the resource identifier:

/SalesOrders/{InvoiceID}

The above URL route when used as a GET operation will retrieve the sales order with the InvoiceID provided:

/SalesOrders/5244dd5e199749f4b6fe

will retrieve sales order with InvoiceID of 5244dd5e199749f4b6fe

The same applies to PATCH and DELETE operations

For POST operations, you don't know and cannot supply the InvoiceID, as it is generated for you - so it is simply a POST to:

/SalesOrders

with the content body being the DTO.

Where there is relational data, such as sales orders have many possible related notes the URL appends to the sales order route URL the plural of the relational data (Notes) and when appropriate the primary key of the note (NoteID). A GET of the following route:

/SalesOrders/5244dd5e199749f4b6fe/Notes

will retrieve all notes for InvoiceID 5244dd5e199749f4b6fe

A POST to the same route will add a new note:

/SalesOrders/5244dd5e199749f4b6fe/Notes

A PATCH to the following route updates the note with NoteID 66581f3f-3efb-4cb5-878c-37f6a55405cf which is attached to sales order with InvoiceID 5244dd5e199749f4b6fe

/SalesOrders/5244dd5e199749f4b6fe/Notes/66581f3f-3efb-4cb5-878c-37f6a55405cf

A DELETE to the same route will remove the note from the sales order

/SalesOrders/5244dd5e199749f4b6fe/Notes/66581f3f-3efb-4cb5-878c-37f6a55405cf



An alternative method of POST or PATCH operations for relational data is not to use the explicit route, but provide the relational data in a POST or PATCH of the parent route.

An example below shows the addition of a new note, the addition of a new line, and the edit of an existing line to an existing sales order using a single PATCH operation to the sales order:

Updates an existing order - adds a new line, adjusts an existing line and adds a note


 ServiceStack Client C#
var client = new ServiceStack.JsonServiceClient("https://api.jiwa.com.au");
var authResponse = client.Get(new ServiceStack.Authenticate() { UserName = "admin", Password = "password" });

var salesOrderPATCHRequest = new JiwaFinancials.Jiwa.JiwaServiceModel.SalesOrderPATCHRequest()
{
	InvoiceID = "babce67cdbf64f778536",
	ExpectedDeliveryDate = DateTime.Now.AddDays(5)                             
};
salesOrderPATCHRequest.Lines.Add(new JiwaFinancials.Jiwa.JiwaServiceModel.SalesOrders.SalesOrderLine { PartNo = "1172", QuantityOrdered = 5 });
salesOrderPATCHRequest.Lines.Add(new JiwaFinancials.Jiwa.JiwaServiceModel.SalesOrders.SalesOrderLine { InvoiceLineID = "88a358a2822e4319b9b9", QuantityOrdered = 10, CustomFieldValues = new List<JiwaFinancials.Jiwa.JiwaServiceModel.CustomFields.CustomFieldValue> { new JiwaFinancials.Jiwa.JiwaServiceModel.CustomFields.CustomFieldValue { SettingID = "1ae102b94dc54dfc8a45                ", Contents = "Adjustment requested by phone" } } });

salesOrderATCHRequest.Notes.Add(new JiwaFinancials.Jiwa.JiwaServiceModel.Notes.Note { NoteText = "Customer telephoned and asked for another few hours of labour" });

var salesOrderATCHResponse = client.Patch(salesOrderPATCHRequest);
 C#
using (var webClient = new System.Net.WebClient())
{
    // Authenticate               
    webClient.QueryString.Add("username", "Admin");
    webClient.QueryString.Add("password", "password");
     
    string responsebody = webClient.DownloadString("https://api.jiwa.com.au/auth");               
    // Above returns something like this: {"SessionId":"0hKBFAnutUk8Mw6YY6DN","UserName":"api","DisplayName":"","ResponseStatus":{}}
 
    // Deserialise response into a dynamic - below requires the Newtonsoft.Json nuget package
    var authResponse = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(responsebody);
    var sessionId = authResponse.SessionId;
 
    webClient.Headers.Add(System.Net.HttpRequestHeader.Cookie, string.Format("ss-id={0}", sessionId));
    webClient.Headers[System.Net.HttpRequestHeader.ContentType] = "application/json";
	
	string json = Newtonsoft.Json.JsonConvert.SerializeObject(new
	{                    
		ExpectedDeliveryDate = DateTime.Now.AddDays(5),
		Lines = new List<object>
		{
			new { PartNo = "1172", QuantityOrdered = 5 },
			new { InvoiceLineID = "88a358a2822e4319b9b9", QuantityOrdered = 10, CustomFieldValues = new List<object> { new { SettingID = "1ae102b94dc54dfc8a45                ", Contents = "Adjustment requested by phone" } } }
		},
		Notes = new List<object>
		{
			new { NoteText = "Customer telephoned and asked for another few hours of labour" }
		}
	});

	responsebody = webClient.UploadString("https://api.jiwa.com.au/SalesOrders/babce67cdbf64f778536", "PATCH", json); 
}
 Curl
curl -H 'Accept: application/json' -H 'Content-Type: application/json' -X GET https://api.jiwa.com.au/auth -d '{"username":"Admin","password":"password"}'

Returns the following authentication response, containing the SessionId which subsequent requests will need to include in the cookie "ss-id"

{"SessionId":"6w1nLX8r0sIrJHClX9Vj","UserName":"Admin","DisplayName":"","ResponseStatus":{}}

Then, with the SessionId now known, the route can be called:

curl -H 'Accept: application/json' -H 'Content-Type: application/json' --cookie 'ss-id=6w1nLX8r0sIrJHClX9Vj' -X PATCH https://api.jiwa.com.au/SalesOrders/babce67cdbf64f778536 -d '{"ExpectedDeliveryDate":"2017-09-20","Lines":[{"PartNo":"1172","QuantityOrdered":5},{"InvoiceLineID":"88a358a2822e4319b9b9","QuantityOrdered":10,"CustomFieldValues":[{"SettingID":"1ae102b94dc54dfc8a45                ", "Contents":"Adjustment requested by phone"}]}],"Notes":[{"NoteText":"Customer telephoned and asked for another few hours of labour"}]}'

The response returned from the above request will be a json document representing the full sales order DTO model from the business logic - see the meta data page for the SalesOrderPATCHRequest for more detail.

Note(1): The DebtorID or DebtorAccountNo can be provided. If both are provided, then the DebtorID will be used to resolve the debtor.

Note(2): A sales order line can update an existing line by providing the InvoiceLineID property. New lines are appended by omitting InvoiceLineID.

Note(3): A new sales order line added can provide either the InventoryID, or the PartNo. If both are provided, then the InventoryID will be used to resolve the inventory item.

Note(4): When sales order lines are added, omitting the price will cause Jiwa to determine the price per normal pricing scheme logic.

Note(5): The last line added in the above example sets a custom line field value for a setting with ID "1ae102b94dc54dfc8a45"

Note(6): When adding notes if the NoteType is omitted, then the default note type configured in Jiwa is used.





Authenticating


API Key Authentication

Jiwa 07.02.00 has added API Key authentication:

https://jiwa.atlassian.net/browse/DEV-6727

https://jiwa.atlassian.net/browse/DEV-6733

Most routes will require authentication. There are 2 methods of authentication - user credential and API Key. API Key authentication was introduced in version 7.2 of Jiwa.

User Credentials Authentication


User credentials authentication is performed by invoking the /auth route and passing the username and password of a Jiwa user.  A successful authentication will return an authentication response containing the SessionId.  All subsequent requests will need to provide the SessionId as the value for the cookie "ss-id".

An alternative to using a cookie, is to send subsequent requests with the header "X-ss-id" set to the SessionId.

Authenticate by calling the /auth route


 ServiceStack Client C#

See Installing the ServiceStackVS Extension for Visual Studio on how to configure your Visual Studio project to use the ServiceStack client needed for this example.

var client = new ServiceStack.JsonServiceClient("https://api.jiwa.com.au");
var authResponse = client.Get(new ServiceStack.Authenticate() { UserName = "admin", Password = "password" });

 C#

using (var webClient = new System.Net.WebClient())
{
    // Authenticate               
    webClient.QueryString.Add("username", "Admin");
    webClient.QueryString.Add("password", "password");
     
    string responsebody = webClient.DownloadString("https://api.jiwa.com.au/auth");               
}

 Curl

curl -H 'Accept: application/json' -H 'Content-Type: application/json' -X GET https://api.jiwa.com.au/auth -d '{"username":"Admin","password":"password"}'

 Web Browser

Navigate to the auth URL and provide the username and password as parameters:

https://api.jiwa.com.au/auth?username=admin&password=password&format=json

This authenticates the user and creates a cookie, so a subsequent request will automatically include the SessionId. Note the &format=json in the above URL this overrides the content type returned. For browsers the default content type is HTML - if a content type override is omitted, then a HTML razor view of the data will be returned instead of json. xml and csv are also valid overrides for the content type to be returned. We only used ?format=json in this example to demonstrate the return value.


The response returned from the above request:

{"SessionId":"6w1nLX8r0sIrJHClX9Vj","UserName":"Admin","DisplayName":"","ResponseStatus":{}}


API Key Authentication


API Keys can be provided either as a HTTP Bearer token in the request header or as a URL or form parameter. There is no authentication step with API Keys, you simply provide the API Key with the request being made.

HTTP Bearer token
curl -H 'Authorization: Bearer znis9fHm0_D5EGRrGdWG7WA2EP7Hke_gloC6R76A2t0' -H 'Accept: application/json' -H 'Content-Type: application/json' -X GET https://api.jiwa.com.au/Debtors



URL Parameter
curl -H 'Accept: application/json' -H 'Content-Type: application/json' -X GET https://api.jiwa.com.au/Debtors?apikey=znis9fHm0_D5EGRrGdWG7WA2EP7Hke_gloC6R76A2t0



As API Keys are associated with a Jiwa staff member, all permissions are that of the staff member - for all intents the permissions are the same as if the authentication was performed with username and password.  API Keys can have an expiration date, and also can be revoked by marking the key as not Enabled. Requests using an expired or revoked key will fail with a 401 Not Authenticated error.

There are 2 types of API Keys in Jiwa 7.2 - Staff API Keys and Debtor API Keys.

Staff API Keys

Staff API Keys are simply an alternate way of a staff member or user authenticating to the username and password. A staff member can have an API key associated with them via the Staff Maintenance form in Jiwa:

Debtor API Keys

Debtor API keys are intended to be given to customers to interact with your Jiwa API to perform such functions as:

  •  

    • Retrieve a filterable, paginated list of products

    • Retrieve a product

    • Retrieve a filterable, paginated list of sales orders

    • Place sales orders

    • Retrieve a sales order

    • Add, edit or remove lines from a sales order

    • Retrieve a filterable, paginated list of sales quotes

    • Place a sales quote (request for quote)

    • Retrieve a sales quote

    • Add, edit or remove lines from a sales quote

    • Retrieve a list of their transactions

    • Retrieve their account record

Debtor API Keys are associated with a debtor via the API Keys tab of the Debtor Maintenance form:

Note that the API Key is linked to a staff member.  When a Debtor API Key is used in a request the API will login into Jiwa as the associated staff member - so it is recommended to create a new user (staff member) with restricted permissions which you should link all your Debtor API Keys to.

Permissions

It is recommended to create a specific user which will be used for Debtor API Keys, and also a specific User Group to which the user belongs to. The REST API permissions for the User Group should be set as shown below:

Recommended Route Exposure

As the Debtor API key is expected to be given to a customer, care must be taken to only expose routes/services necessary and not to leak sensitive information. You must not trust any request using a Debtor API Key, and so validation and filtering must be performed within the REST API.

By default the REST API plugin will filter some requests and responses to prevent unwanted information disclosure. The following lists which routes currently filter the requests and responses:

Route

Summary

Verb

Request Filtering Performed

Response Filtering Performed

Route

Summary

Verb

Request Filtering Performed

Response Filtering Performed

 /Inventory/{InventoryID}

Retrieves an inventory item

GET 

 None

  •  

    •  

      •  

        • Removes costs

        • Removes debtor specific prices for other debtors

        • Removed debtor classifaction prices for other debtors

 /Queries/SalesOrderList

Retrieves a list of sales orders

 GET

Filtered on DebtorID

 None

 /SalesOrders

 Creates a new sales order

 POST

DebtorID replaced

CreditNote flag removed

InvoiceInitDate removed

SystemSettings removed

Payments Removed

Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPrice

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • FixPrice

        • FixSellPrice

        • TaxRate

        • TaxToCharge

        • UnitCost

        • Line Details

        • QuantityBackOrd

        • QuantityThisDel

 Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • TaxRate.LedgerAccount

        • UnitCost

        • Line Details Cost

        • Line Details SOHID

        • Line Details SpecialPrice

 /SalesOrders/{InvoiceID}

Retrieves a sales order

 GET

Filtered on DebtorID

SystemSettings removed

Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • TaxRate.LedgerAccount

        • UnitCost

        • Line Details Cost

        • Line Details SOHID

        • Line Details SpecialPrice

 /SalesOrders/{InvoiceID}

Updates a sales order

PATCH

DebtorID replaced

CreditNote flag removed

InvoiceInitDate removed

SystemSettings removed

Payments Removed

Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPrice

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • FixPrice

        • FixSellPrice

        • TaxRate

        • TaxToCharge

        • UnitCost

        • Line Details

        • QuantityBackOrd

        • QuantityThisDel

SystemSettings removed

Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • TaxRate.LedgerAccount

        • UnitCost

        • Line Details Cost

        • Line Details SOHID

        • Line Details SpecialPrice

/SalesOrders/{InvoiceID}/Save

Saves a stateful sales order

GET

Filtered on DebtorID

Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • TaxRate.LedgerAccount

        • UnitCost

        • Line Details Cost

        • Line Details SOHID

        • Line Details SpecialPrice

/SalesOrders/{InvoiceID}/Abandon

Abandons a stateful sales order

DELETE

Filtered on DebtorID

None

/SalesOrders/{InvoiceID}/Historys/{InvoiceHistoryID}/Lines/{InvoiceLineID}

Retrieves a sales order line

GET

Filtered on DebtorID of Sales Order

Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • TaxRate.LedgerAccount

        • UnitCost

        • Line Details Cost

        • Line Details SOHID

        • Line Details SpecialPrice

/SalesOrders/{InvoiceID}/Historys/{InvoiceHistoryID}/Lines

Appends a line to a sales order

POST

Filtered on DebtorID of Sales Order

Removes the following from the sales order line:

  •  

    •  

      •  

        • DiscountedPrice

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • FixPrice

        • FixSellPrice

        • TaxRate

        • TaxToCharge

        • UnitCost

        • Line Details

        • QuantityBackOrd

        • QuantityThisDel



Removes the following from sales order lines:

  •  

    •  

      •  

        • DiscountedPercentage

        • DiscountGiven

        • PriceExGst

        • PriceIncGST

        • TaxRate.LedgerAccount

        • UnitCost

        • Line Details Cost

        • Line Details SOHID

        • Line Details SpecialPrice

/SalesOrders/{InvoiceID}/Historys/{InvoiceHistoryID}/Lines/{InvoiceLineID}

Updates a sales order line

PATCH

Filtered on DebtorID of Sales Order