Skills gained:
knowledge of available ABRA Flexi URL parameters
knowledge of the most complex URL constructions
In the previous, very theory-heavy chapter, we showed how a Flexi API URL is constructed and what parts it consists of. In this training, we will demonstrate more advanced and highly effective techniques for retrieving data via the Flexi API.
We will essentially cover two parts of the URL: the parameters at the end of the address and data filtering — including combining multiple parameters at once and building compound filters, which will put even the logical thinking of an API Ninja to the test. Once again, we will walk through examples at three levels of complexity — let's get started!
Level: Apprentice
We already know how to build a correct URL for Flexi. Let's move straight to filtering examples. Simple filtering is possible on virtually any field in a given register. As shown in the previous chapter, the fields for a given register can be found in /properties, which can be called on any register from /evidence-list.
We also already know where filters are placed in the URL from the previous article. Let's try the first simple example: filtering orders in EUR. According to /properties for received orders, we can see that the currency field (mena) uses IdMeny values, so we first need to find out what ID the EUR currency has. Since we know the EUR currency code, we can use a simple filter:
No more complex construction is needed. This returns the currency record from the currency code list, including its ID.
<winstrom version="1.0">
<!-- Měny -->
<mena>
<!-- ID (celé číslo) - -->
<id>11</id>
<!-- Poslední změna (datum a čas) - -->
<lastUpdate>2006-10-20T00:00:00+02:00</lastUpdate>
<!-- Zkratka (řetězec) - max. délka: 20 -->
<kod>EUR</kod>
<!-- Název (řetězec) - max. délka: 255 -->
<nazev>Euro</nazev>
</mena>
</winstrom>
Now we know that the currency ID is 11, so we can build a query for orders that are in euros.
This example shows that what matters is not only the field name, but also the values that field can hold. It is therefore important to enter the search values correctly: numbers can simply be written on their own, while text strings must be enclosed in quotation marks or apostrophes. You can enter numbers, text strings, and boolean values this way. Dates, date+time values, and other functions will be shown later.
It may be useful to filter orders (or other documents) for a specific company, but you don't know its full company registration number or company name — you only happen to know that the registration number started with 9. How do you handle that? Consider an example where you know about orders from a company called Kolbas, but the call returns nothing with a similar company code:
Note that a code from another register must be specified using "code:"
To find records for which you only have partial information, you can use filters such as begins, ends, between, like, in and others. In our case, begins or like (contains) "Kol" will do the job:
Another example call:
This call returns all orders from a customer whose registration number starts with nine. However, there may be more than just the Kolbas we're looking for — so how do you filter by multiple criteria at once? We'll cover that in the final level.
Apprentice, these are the basics of filtering —
try out more examples; there are many filters available.
Another powerful tool for every API Ninja is parameters. It is useful to sort results as needed, display only the amount of data you require, or find out how many results were returned. Let's sort orders by issue date, retrieve only basic order information, and find out how many orders there are in total. The call looks like this:
Let's break it down. Immediately after the register code comes the format ".xml", since we want all orders and no filter criteria are needed. As we already know, parameters are placed after the question mark. The "order" parameter accepts the name of the field from the given register by which we want to sort, along with the sort direction: @A - ascending and @D - descending. Additional parameters are appended to the address using the "&" character, which introduces each subsequent parameter. The next parameter is "detail=summary", which specifies that we only want a basic summary of order information.
The last parameter is the special parameter "add-row-count=true". This returns the rowCount=number of results in the root element <winstrom>.
The most interesting parameter used here is "detail". Its more advanced and recommended usage is "detail=custom( … )", which we will demonstrate below. In the previous article, we showed how to retrieve a PDF via the API — we can now extend that example to retrieve a PDF in English.
Can we retrieve a document for a client in English via the API?
And English-language documents for the Kolbas client — we already looked up their details above, so we know how to filter. We get two PDFs:
Where did we get obchodDokladVystupniOBP? We already know that from last time, Apprentice. :-)
Level: Warrior
A Warrior working with the Flexi API needs to go deeper and master additional techniques on the path to becoming an API Ninja. We will cover more advanced parameters and filters — advanced in terms of practical application rather than in understanding. Let's dive in.
A Warrior who is already more familiar with the Flexi API will naturally wonder how to work with dates, relationships, and large result sets that can number in the thousands. We touched on relationships in the previous training; now let's look at some examples. How do you filter a price list together with its associated stock cards?
This query returns all price list items, including their stock cards. However, when there are many results, we can use pagination via the "limit" and "start" parameters.
This API query returns 3 results, but skips the first three. If you genuinely want all results, you must always specify limit=0, as the default response returns only 20 results.
Which first three were skipped? (By default, without any sorting, results are ordered by ID — so the first three with the lowest ID.)
If you are writing your own scripts, you will certainly find the special functions built into the FlexiBee API useful. The first of these is the me() function, which retrieves all (limit = 0) records belonging to the currently logged-in user.
Others work with dates. To dynamically retrieve records that are older than the current date and time, use the now(). function. To dynamically retrieve records for the current year, use the currentYear() function — useful for validating certain records, such as entries in code lists.
What remains at the Warrior level is to cover how to query by a specific date. Dates are entered in the format YYYY-MM-DD, e.g. 2018-11-01, and date+time values in the format YYYY-MM-DD'T'HH:MM:SS[.sss], e.g. 2018-11-03T12:30:00. So if we want to filter orders that arrived by Valentine's Day morning and we want to process them in time, the call would look like this:
Now all that remains is to combine everything we've learned — all manner of parameters and extensive filters. A task made for an API Ninja.
Level: Ninja
We already know all the key options from the previous levels — now all we need to do is combine them. Without further ado, let's tackle the first challenge: combining filters. We'll start right at the deep end, with a big combination.
Imagine a scenario where we want to find all (how many) deposit and "regular" invoices that are overdue as of today, do not have a label indicating they should not be reminded, and have already been reminded once. At the same time, we only want our own summary information, including the debtor's name and the amount owed — all sorted from the oldest and highest outstanding amount. To achieve such a query, we need to use the logical operators or and and, as well as the standard equals and not-equals operators. Without URL-encoding of spaces, the query looks like this:
Feeling overwhelmed, Ninja? Not at all — what matters is organizing your input information clearly. The order of filters and parameters does not matter. However, there are a few things we need to keep in mind that we already know:
logical thinking :-)
We want to retrieve documents of type INVOICE or DEPOSIT, where the due date is in the past, a first reminder date has already been set, they do not have the specific label DO-NOT-REMIND, they are not cancelled, and the payment status is either empty or only partially paid. We have a custom detail query, and the interesting part is the nested detail "firma(nazev)", which tells the API that from includes=faktura-vydana/firma we only want to display the company name. Then it's just a matter of sorting and printing the record count.
Was that example exhausting, or can you come up with another one — for instance, an interesting warehouse query, Ninja?
What the above encoded query means, an API Ninja will surely figure out.
There are additional special parameters that every API Ninja should know, especially when integrating Flexi with other systems. Flexi outputs include identifiers for every object. It may be desirable to remove these identifiers, which is what the "?no-ids=true" parameter is for. You may also have come across the ?only-ext-ids=true parameter. What is the difference between them?
The "?only-ext-ids=true" parameter also affects sub-registers — try incorporating it into the previous examples and compare the results.
A related parameter is "?code-as-id=true". This parameter causes the record's code to be output as its ID. By combining the parameters "?only-ext-ids=true&code-as-id=true", you can optimize performance and prepare data for import into another system without Flexi's internal IDs.
The last parameters we will cover in this training are "?dry-run=true" and "?auth". Imagine a situation where you are performing an advanced write operation in Flexi but are unsure of the outcome, or you simply need to retrieve a calculated value. That is exactly what the "?dry-run=true" parameter is for. The action is executed but not saved to Flexi, allowing you to verify the result. In addition, you will receive in the tag <content /> the resulting representation of the record exactly as it would look if it had been saved.
Maintaining authentication from the application when calling the Flexi API in your script is a handy technique for every API Ninja. If you want to use a Flexi login for multiple calls in an external application, you can use a so-called authentication token. You obtain it by making a POST request to: https://developer.flexibee.eu//login-logout/login.json
The request body must contain:
{
"username": "ninja",
"password": "heslo"
}
Ninja, try it out in Postman or using cURL!
The Flexi API will return the aforementioned token in its response:
{
"authSessionId":"fd574d06addd928bd059e50ff51ab966764873d5fe5598cece77ce7bb49674ae",
"refreshToken":"quTDI5rkBkoZ6czPOH1wM/lFzbPEVJhyFat5ju4hF2g=",
"csrfToken":"78feef28-7343-4f32-bac5-ff2ad03703fd",
"success":true
}
The authSessionId returned can then be used in your script — for example in PHP — to authenticate with Flexi. If you use HTTPFul, which was mentioned in an earlier training, it might look something like this.
$cenik = \Httpful\Request::get ('https://developer.flexibee.eu/c/ninja/cenik.xml?only-ext-ids=true')
->sendsJson()
->withoutStrictSsl()
->addHeader('X-authSessionId', $authSessionId)
->send();How long can I use the token? Does the session last forever?
The token occasionally needs to be refreshed. To keep the token valid, you need to maintain the session by periodically making a GET call to /login-logout/session-keep-alive.js.
Approximately every 30 minutes should be sufficient.
The API Ninja keeps exploring and discovering! What about logging out a user?
This training covers the basic, most commonly used parameters and filters. You can find more in our standard documentation: Filtering, Building URLs, and authentication details. Next, we will look at supported formats and how to send them.












