Playing with Ibanity (continued)¶
Thursday, January 23, 2025
Geoffrey helped me to find the mistakes in my yesterday script:
content type should be application/vnd.api+json
, there was a mistake in my
URL, and the payload should get specified using the json
keyword argument
instead of data
(I didn’t know this argument, so I looked up the API docs).
Here, finally, is the working script:
# See https://luc.lino-framework.org/blog/2025/0123.html
from pathlib import Path
import requests
import base64
import sys
import json
import uuid
from pprint import pprint
# Define client ID and secret
client_id = "69d85961-7d68-474d-9ac2-426fdc71bab8"
client_secret = "valid_client_secret"
# Define certificate and key file paths
cert_dir = Path(f"~/Documents/ibanity/application_{client_id}/").expanduser()
cert_file = cert_dir / "certificate.pem"
key_file = cert_dir / "decrypted_private_key.pem"
# Validate if the key and certificate files exist
if not cert_file.exists():
raise Exception(f"Error: Certificate file not found at {cert_file}")
if not key_file.exists():
raise Exception(f"Error: Private key file not found at {key_file}")
# Base64 encode client_id and client_secret for Basic Auth
client_credentials = f"{client_id}:{client_secret}"
encoded_credentials = base64.b64encode(client_credentials.encode()).decode()
# Create an HTTPS session
s = requests.Session()
# Attach client certificate and key to the session
s.cert = (cert_file, key_file)
# Add the Authorization header
headers = {
"Authorization": f"Basic {encoded_credentials}",
"Content-Type": "application/x-www-form-urlencoded", # Required for OAuth2 requests
}
url = "https://api.ibanity.com/einvoicing/oauth2/token"
data = {"grant_type": "client_credentials"}
response = s.post(url, data=data, headers=headers)
if response.status_code != 200:
raise Exception(f"Unexpected response status code: {response.status_code}\n{response.text}")
rv = json.loads(response.text)
access_token = rv['access_token']
# Customer search. Check whether my customer exists.
# Belgian participants are registered with the Belgian company number, for which
# identifier 0208 can be used. Optionally, the customer can be registered with
# their VAT number, for which identifier 9925 can be used.
print("Customer search")
url = "https://api.ibanity.com/einvoicing/peppol/customer-searches"
eas = "9925"
vat_id = "BE0010012671"
# The Flowin sandbox contains hard-coded fake data. Using another reference as
# customerReference will in result a 404
headers = {
"Accept": "application/vnd.api+json",
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/vnd.api+json"
}
# pprint(headers)
data = {
"type": "peppolCustomerSearch",
# "id": str(uuid.uuid4()),
"attributes": {
"customerReference": f"{eas}:{vat_id}",
# "supportedDocumentFormats": doc_formats
}
}
data = {"data": data}
# pprint(data)
response = s.post(url, headers=headers, json=data)
if response.status_code != 200:
msg = f"POST {url} returned {response.status_code}\n{response.text}\n"
raise Exception(msg)
rv = json.loads(response.text)
pprint(rv)
And here is the output:
$ python docs/blog/2025/0123.py
Customer search
{'data': {'attributes': {'customerReference': '9925:BE0010012671',
'supportedDocumentFormats': [{'customizationId': 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0',
'localName': 'Invoice',
'profileId': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
'rootNamespace': 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2',
'ublVersionId': '2.1'},
{'customizationId': 'urn:cen.eu:en16931:2017#conformant#urn:UBL.BE:1.0.0.20180214',
'localName': 'Invoice',
'profileId': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
'rootNamespace': 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2',
'ublVersionId': '2.1'},
{'customizationId': 'urn:cen.eu:en16931:2017#conformant#urn:UBL.BE:1.0.0.20180214',
'localName': 'CreditNote',
'profileId': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
'rootNamespace': 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2',
'ublVersionId': '2.1'},
{'customizationId': 'urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0',
'localName': 'CreditNote',
'profileId': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
'rootNamespace': 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2',
'ublVersionId': '2.1'},
{'customizationId': 'urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0',
'localName': 'Invoice',
'profileId': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
'rootNamespace': 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2',
'ublVersionId': '2.1'},
{'customizationId': 'urn:cen.eu:en16931:2017#compliant#urn:fdc:nen.nl:nlcius:v1.0',
'localName': 'CreditNote',
'profileId': 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0',
'rootNamespace': 'urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2',
'ublVersionId': '2.1'}]},
'id': '99988e77-cc4a-4583-bd4a-288095c5566e',
'type': 'peppolCustomerSearch'}}
Okay so far. Now let’s go on.