vrijdag 15 november 2019

Exact Online - Python - REST API

Recently I was asked to make a local application to import contacts from a CSV file to Exact Online. This should run automatically whenever a new CSV is available.
Python (2.7) is the language I wanted to use.
A library is available (https://github.com/ossobv/exactonline), but I needed some time to implement the OAuth2.
No real examples are available, so I decided to make a step by step tutorial.

Go to the Exact Online Developers site: https://www.exact.com/benl/developers
Click on "Exact Online Partners" to create a free account:



Now go to the App center and login: https://apps.exactonline.com/be/nl-BE/V2

At the top, right side, you can click on "Mijn Apps beheren" (Control my apps).
Now create a new "Test-App":



Give a name and set the Redirect URI to: https://app.getpostman.com/oauth2/callback (I will get back to this later on):



Click register and find the authorization data:



You need the "Client ID" and "Client Secret" later on.

Now you need to create an access token. You might be able to do this with your webserver, but I used another easy solution:
Install Postman on your computer: https://www.getpostman.com/
Create a new request:



Now choose "Authorization" -> type: "OAuth 2.0" -> "Get New Access Token":



Fill out the fields in the form. "Client ID" and "Client Secret" are the ones you created before. All other fields should be the same (unless you're not in Belgium: exactonline.be):



When you click "Request Token", you will be directed to the login screen of Exact Online. Use the developer credentials you created earlier:



Postman will show you the "Tokens" now:



The tokens will expire after one hour. You can make new ones if this should happen.

Now it's Python time. Install the ExactOnline library: pip install exactonline
We need to setup the configuration in the INI file. An example is included in the library:
exactonline/exactonline/storage/ini_example.ini


 [server]  
 auth_url = https://start.exactonline.co.uk/api/oauth2/auth  
 rest_url = https://start.exactonline.co.uk/api  
 token_url = https://start.exactonline.co.uk/api/oauth2/token  
   
 [application]  
 base_url = https://example.com  
 client_id = {12345678-abcd-1234-abcd-0123456789ab}  
 client_secret = ZZZ999xxx000  
 iteration_limit = 50  
   
 [transient]  
 access_expiry = 1426492503  
 access_token = dAfjGhB1k2tE2dkG12sd1Ff1A1fj2fH2Y1j1fKJl2f1sD1ON275zJNUy...  
 code = dAfj!hB1k2tE2dkG12sd1Ff1A1fj2fH2Y1j1fKJl2f1sD1ON275zJNUy...  
 division = 123456  
 refresh_token = SDFu!12SAah-un-56su-1fj2fH2Y1j1fKJl2f1sDfKJl2f1sD11FfUn1...  

I changed the server part to match the Belgian Exact Online:

 [server]  
 auth_url = https://start.exactonline.be/api/oauth2/auth  
 rest_url = https://start.exactonline.be/api  
 token_url = https://start.exactonline.be/api/oauth2/token  

In the "Application" part, mind the incorrect curly braces (client_id). I wasted some time looking for this error. Here is the correct way:

 [application]  
 base_url = https://app.getpostman.com/oauth2/callback  
 client_id = 5d999999-9999-9999-9999-999999999761  
 client_secret = vL********Ky  
 iteration_limit = 50  

And the last part. Put the access_token and the refresh_token inplace.
The division you can find by browsing to: https://start.exactonline.be/docs/XMLDivisions.aspx (Do this while you are logged in at Exact Online (https://start.exactonline.be).

 [transient]  
 access_token = gAAAAJ0Tfk9999999999999999999sOFJ6ESyLhWnTIlMvOvsHwJ-99999999999999999999wpw8q_UikFez3GcLVpiYPTLOQ12f6scck6O0h1Bk8TWSB1naDpNcEG9KtfIB9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999_H5YiUjK0zkmAEaXyGcbqxgYVBLtgReiS-elZEllm9tnI2iyeNiL8nGrlzRVyD9Ev6_ejqlfYKBopI1tb2lAndz54tNuaif3-r84CQ91N4LjvlLO6T8kg8AE9MB4RnSD4Z5R97QDVH2pQlmsRVmTC7jKTXaH4MH_B-89FxmZq7pp_d9GGg6-QBEYTRHWfoTJJfApZxPRGP9yjhYJTJf4fjf5MlQhOo3DlPNKO5gJQCy0_YNMwA688L0fnkyo16Hcj-Hp4wsMuPOiuBEcXQI4MH68idj58Z2DVt2w0dBNM_R8RbA3wJEQ_dowW6owLlJACOX8Dt_M1zcZzOnIlwg94Z4o9999999999999999999999999999999999999999999999999999999999999999999999999999999999999990YM  
 division = 425880  
 refresh_token = O4D999999999999999999999999999999999999999999999999999999999999999999985liyY9HzVZ3w0lrgqhdjqwU-bDD-5NsNanWG_LDm3_jCW6sAhDXvpzlB8KGbKpTNEPgIFm9DwBFuHhocdTZ7Fzt4UHp-C4KmTRMM1s8v5v8BtcZfqbAKKV14mX9PoOahQ2E2GFhrs7h4cqESHHdvYLOdui3vzcndGsLLT3P-YJd52P4iTWtKmAi-l2t3NWKX3HQYSQGRXjQcS_dFeTV0ZH5L979UJ99999999999999999999999999999999999999999999999999999999999999999999999999999GooQ  

Save this to "config.ini"

Everything should be allright now. Try following code (change the path to the ini file):

 from exactonline.api import ExactApi  
 from exactonline.exceptions import ObjectDoesNotExist  
 from exactonline.resource import GET, POST, PUT, DELETE  
 from exactonline.storage.ini import IniStorage  
   
 # Create a function to get the api with your own storage backend.  
 def get_api():  
   storage = IniStorage('c:/Python27/exact/config.ini')  
   return ExactApi(storage=storage)  
 api = get_api()  
   
 relations = api.relations.filter(top=100)  
 print(relations)  
   

This is the start. The ini file will be automatically refreshed with new tokens as they expire.

Whenever you need to use this in the client's production evironment, you can create the same tokens with their credentials. Also change the devision.

Drop me a line if you need more code.

16 opmerkingen:

  1. Reacties
    1. Super! Glad if it helped you.

      Verwijderen
    2. HI, perhaps someone can help me out to make this easy to use.
      i want to get and sync data between odoo and exact online.

      Thanks in advance,

      Ricky

      Verwijderen
  2. eeuwig dankbaar in tegenstelling tot de zure documentatie van Exact werkt nog steeds!

    BeantwoordenVerwijderen
  3. Hi Pieter thanks a lot for sharing this information. I am left with one question, my access_token in the config.ini is not refreshing automatically. Do you mind helping me, maybe share your code?

    BeantwoordenVerwijderen
    Reacties
    1. Sorry, didn't see your message earlier. With the code you see, it should update.
      It might be a permission problem, especially when not using Windows. Otherwise I need more details.

      Verwijderen
  4. Beste Pieter,

    Ik heb een probleem met de redirect uri.....
    Wat ik ook probeer het lukt maar niet....

    Lokaal op windows machine gaat prima, maar zit nu ook extern met SSL verbiding. Ik kom t/m het inlogscherm en code invoeren, maar daarna gaat het finaal mis....

    Het is iets met de redirect uri waar ik gewoon niet mee uit kom.

    Alvast bedankt.
    Mvg,

    Ricky

    BeantwoordenVerwijderen
    Reacties
    1. Dag Ricky,
      Ik begrijp niet direct wat je bedoelt met extern en met SSL verbinding.
      Die redirect heb je maar 1 keer in het begin nodig. Bvb lokaal. Zodra je de keys hebt, kan je dat overal met die keys laten werken (de eerste binnen het uur ofzo).
      Tenzij dat je beooelt om het te laten werken voor verschillende gebruikers. Dan zal je dit op een andere manier moeten activeren (bv Python met Flask, maar dat brengt ons hier te ver).

      Verwijderen
    2. Beste Pieter,

      Bedankt voor je reactie. Ik had het niet eerder gezien en ben er vandaag weer mee begonnen.

      Aan de hand van de vb functie krijg ik wel een link nu in mijn windows terminal. Ik zou hier als het goed is een web pagina moeten krijgen om in te loggen bij exact. Dat krijg ik niet.

      Of is dat niet de bedoeling ?

      Mvg,

      Ricky

      Verwijderen
  5. Beste Pieter,
    ik heb deze stappen uitgevoerd en ik kan perfect bepaalde transacties boeken in de developer omgeving.
    Mijn vraag is nu, hoe krijg ik dit python script actief voor mijn live dossiers?
    is het verplicht om die goedkeuringsstappen van Exact Online te doorlopen?

    Bedankt.

    mvg,
    Riyanto

    BeantwoordenVerwijderen
  6. Dear Pieter,

    Thanks a lot, this is a life saver, only clear documentation I could find imho.

    For other people still trying to get this working: I got it working in Aug 2022. For those working on mac, at first the api returned an SSL error (URLError: )

    The answer by TJ1 on https://stackoverflow.com/questions/68275857/urllib-error-urlerror-urlopen-error-ssl-certificate-verify-failed-certifica helped me solve this.

    Good luck ;)

    BeantwoordenVerwijderen
    Reacties
    1. If anyone is interested, I can put another post online to get tokens without Postman. Python and Flask to get login/pass from users.

      Verwijderen
    2. Hi Pieter, That would be very interesting indeed!

      Verwijderen
    3. I would love to!

      Verwijderen
  7. Hi, I get an error saying ""lang": "", "value": "Forbidden - WrongDivision". Any idea?

    BeantwoordenVerwijderen