Invoicing API
1. Overview
Jakamo Invoicing API allows suppliers to send invoices via Jakamo.
1. Getting started
Example 1: Sample bash shell script using Oauth2 authentication
- First setup an Oauth2.0 application with Invoice.write and Invoice.read scopes
- See OAuth2.0 for the tokenUrl and scope parameters
- Jq library is required for parsing json, in most linux distributions this can be installed as
sudo apt-get install jq
#!/bin/bash
# Client id of the oauth 2 app
clientId=...
# Client secret of the oauth 2 app
clientSecret=...
# Authentication constants, lookup values from Oauth2 documentation
tokenUrl=...
scope=...
# Select demo or production Jakamo
jakamoUrl=https://demo.thejakamo.com #demo
#jakamoUrl=https://www.thejakamo.com #production
# Create an authorization token
tokenResponse=$(curl -sX POST $tokenUrl -d "scope=$scope&client_id=$clientId&client_secret=$clientSecret&grant_type=client_credentials")
accessToken=$(jq -r '.access_token' <<<"$tokenResponse")
hasInvoice=true
while [ "$hasInvoice" = "true" ];
do
tmpfile=$(mktemp)
invoiceResponse="$(curl -s -D $tmpfile $jakamoUrl/api/v2/queues/invoices -H "Authorization: Bearer $accessToken")"
if [[ $invoiceResponse == *"<status>No more messages available.</status>"* ]]; then
echo "No more invoices in queue!"
hasInvoice=false
fi
if [ "$hasInvoice" = "true" ]; then
# Read the x-acknowledge-uri header from temporary file and remove it
xAcknowledgeUri=$(grep 'x-acknowledge-uri:' $tmpfile|sed 's/^.*: //')
xAcknowledgeUri=${xAcknowledgeUri::-1}
rm $tmpfile
# Read invoice number from response and save invoice to file
sellerVatNumber=$(grep -oP '(?<=<SellerPartyIdentifier>).*?(?=</SellerPartyIdentifier>)' <<<"$invoiceResponse")
invoiceNumber=$(grep -oP '(?<=<InvoiceNumber>).*?(?=</InvoiceNumber>)' <<<"$invoiceResponse")
currentTime=$(date +%s%3N)
filename="${sellerVatNumber}_${invoiceNumber}_${currentTime}.xml"
echo "Writing $filename"
echo $invoiceResponse > $filename
# Clear invoice from queue
curl -X POST "${xAcknowledgeUri}" -H "Authorization: Bearer $accessToken"
# All set
echo "Cleared invoice $invoiceNumber from queue"
fi
done
Example 2: Sample powershell script using Oauth2 authentication
This powershell script can be scheduled to run at some interval (5-15 minutes). It will fetch all pending invoices from queue and save them to a file. It also has some basic error handling and will abort if the api returs a 2xx status code.
Here it is assumed that invoice numbers are unique for each vendor within certain time period. Invoices are saved in a file named after the vendor VAT id and invoice number to prevent duplicates in case there is an error while removing the invoice from queue.
See OAuth2.0 for the tokenUrl and scope parameters
# Client id of the oauth 2 app
$clientId = ""
# Client secret of the oauth 2 app
$clientSecret = ""
# Authentication constants
$tokenUrl = ""
$scope = ""
$jakamoUrl = "https://demo.thejakamo.com" #demo
#$jakamoUrl= "https://www.thejakamo.com" #production
# Create an authorization token
$tokenResponse = Invoke-RestMethod -Uri $tokenUrl -Method Post -Body @{
scope = $scope
client_id = $clientId
client_secret = $clientSecret
grant_type = "client_credentials"
}
$accessToken = $tokenResponse.access_token
# Set maxcalls to some reasonable value to limit number of invoices fetched in one iteration
$maxCalls = 100
$i = 0
$hasInvoice = $true
while ($hasInvoice -and ($i -lt $maxCalls)) {
$i++
# Read invoice from queue
try {
$invoiceResponse = Invoke-WebRequest -Uri "$jakamoUrl/api/v2/queues/invoices" -Method Get -Headers @{
Authorization = "Bearer $accessToken"
}
} catch
{
# abort script execution on non 2xx code
throw
}
# See if there was an invoice in the queue
if ($invoiceResponse -inotmatch "Finvoice") {
Write-Host "No more invoices in queue!"
$hasInvoice = $false
}
if ($hasInvoice) {
# Read the x-acknowledge-uri header from response
$xAcknowledgeUri = $null
$xMessageUri = $null
$invoiceResponse.Headers.GetEnumerator() | ForEach-Object {
if ($_.Key -eq "x-acknowledge-uri") {
$xAcknowledgeUri = $_.Value
}
if ($_.Key -eq "x-message-uri") {
$xMessageUri = $_.Value
}
}
# Read invoice message identifier and save invoice to file
$messageIdentifier = [regex]::Match($invoiceResponse, '(?<=<MessageIdentifier>).*?(?=</MessageIdentifier>)').Value
$messageIdentifier = $messageIdentifier.Replace(':','-');
$filename = "${messageIdentifier}.xml"
Write-Host "Writing $filename"
try {
# Read invoice bytes from remote uri, preserve encoding
Invoke-WebRequest -Uri $xMessageUri -OutFile $filename -Method Get -Headers @{
Authorization = "Bearer $accessToken"
}
# Clear invoice from queue
$response=Invoke-RestMethod -Uri $xAcknowledgeUri -Method Post -Headers @{
Authorization = "Bearer $accessToken"
}
# All set
Write-Host "Cleared message $messageIdentifier from queue"
# Finvoice stores attachments in a xml file as base64 encoded strings. Decode them for transfer
if ($messageIdentifier -Match "attachments")
{
$index=1
$invoiceIdentifier = $messageIdentifier.Replace("--attachments","")
Select-Xml -Path $filename -XPath "/FinvoiceAttachments/AttachmentDetails" | ForEach-Object -Process {
$base64=$_.Node.AttachmentContent
$mimeType=$_.Node.AttachmentMimeType
switch ($mimeType) {
"image/jpeg" { $fileIdentifier = "jpg" }
"image/png" { $fileIdentifier = "png" }
"application/pdf" { $fileIdentifier = "pdf" }
default { throw "Invalid mimetype" }
}
$attachmentNumber = $index.ToString("000")
$attachmentName = "liite_${invoiceIdentifier}_${attachmentNumber}.${fileIdentifier}"
Write-Host "Writing $attachmentName"
[Convert]::FromBase64String($base64) | Set-Content $attachmentName -Encoding Byte
$index++
}
# We don't need the attachments xml file
Write-Host "Deleting attachments xml ${filename}"
Remove-Item $filename
}
}
catch
{
# abort script execution on non 2xx code
throw
}
}
}
Example 3: Decode attachments from base64 encoded attachments file
Finvoice stores attachments in a xml file as base64 encoded strings. If this cannot be directly utilized, here's a version of the powershell script that decodes those files into their own files.
# Client id of the oauth 2 app
$clientId = ""
# Client secret of the oauth 2 app
$clientSecret = ""
# Authentication constants
$tokenUrl = ""
$scope = ""
$jakamoUrl = "https://demo.thejakamo.com" #demo
#$jakamoUrl= "https://www.thejakamo.com" #production
# Create an authorization token
$tokenResponse = Invoke-RestMethod -Uri $tokenUrl -Method Post -Body @{
scope = $scope
client_id = $clientId
client_secret = $clientSecret
grant_type = "client_credentials"
}
$accessToken = $tokenResponse.access_token
# Set maxcalls to some reasonable value to limit number of invoices fetched in one iteration
$maxCalls = 100
$i = 0
$hasInvoice = $true
while ($hasInvoice -and ($i -lt $maxCalls)) {
$i++
# Read invoice from queue
try {
$invoiceResponse = Invoke-WebRequest -Uri "$jakamoUrl/api/v2/queues/invoices" -Method Get -Headers @{
Authorization = "Bearer $accessToken"
}
} catch
{
# abort script execution on non 2xx code
throw
}
# See if there was an invoice in the queue
if ($invoiceResponse -inotmatch "Finvoice") {
Write-Host "No more invoices in queue!"
$hasInvoice = $false
}
if ($hasInvoice) {
# Read the x-acknowledge-uri header from response
$xAcknowledgeUri = $null
$xMessageUri = $null
$invoiceResponse.Headers.GetEnumerator() | ForEach-Object {
if ($_.Key -eq "x-acknowledge-uri") {
$xAcknowledgeUri = $_.Value
}
if ($_.Key -eq "x-message-uri") {
$xMessageUri = $_.Value
}
}
# Read invoice message identifier and save invoice to file
$messageIdentifier = [regex]::Match($invoiceResponse, '(?<=<MessageIdentifier>).*?(?=</MessageIdentifier>)').Value
$messageIdentifier = $messageIdentifier.Replace(':','-');
$filename = "lasku_${messageIdentifier}.xml"
Write-Host "Writing $filename"
try {
# Read invoice bytes from remote uri, preserve encoding
Invoke-WebRequest -Uri $xMessageUri -OutFile $filename -Method Get -Headers @{
Authorization = "Bearer $accessToken"
}
# Clear invoice from queue
$response=Invoke-RestMethod -Uri $xAcknowledgeUri -Method Post -Headers @{
Authorization = "Bearer $accessToken"
}
# All set
Write-Host "Cleared message $messageIdentifier from queue"
# Finvoice stores attachments in a xml file as base64 encoded strings. Decode them for transfer
if ($messageIdentifier -Match "attachments")
{
$index=1
$invoiceIdentifier = $messageIdentifier.Replace("--attachments","")
Select-Xml -Path $filename -XPath "/FinvoiceAttachments/AttachmentDetails" | ForEach-Object -Process {
$base64=$_.Node.AttachmentContent
$mimeType=$_.Node.AttachmentMimeType
switch ($mimeType) {
"image/jpeg" { $fileIdentifier = "jpg" }
"image/png" { $fileIdentifier = "png" }
"application/pdf" { $fileIdentifier = "pdf" }
default { throw "Invalid mimetype" }
}
$attachmentNumber = $index.ToString("000")
$attachmentName = "liite_${invoiceIdentifier}_${attachmentNumber}.${fileIdentifier}"
Write-Host "Writing $attachmentName"
[Convert]::FromBase64String($base64) | Set-Content $attachmentName -Encoding Byte
$index++
}
# We don't need the attachments xml file
Write-Host "Deleting attachments xml ${filename}"
Remove-Item $filename
}
}
catch
{
# abort script execution on non 2xx code
throw
}
}
}