Carrying trade information in the sky
EasyUBL is the programmer's choice of REST-APIs for easy integration to the Peppol (Pan-European Public Procurement OnLine) network.Send Peppol documents through EasyUBL providing only the absolute minimum necessary information. EasyUBL takes care of the rest.
Receive Peppol documents through EasyUBL and enjoy the AI accounting proposals delivered with a json document version in addition to the raw XML document and a human-readable versions (PDF or HTML).
To work with EasyUBL API you have to be a tenant.
As a tenant, you can set up companies that can send and receive documents. A tenant could, for example, be the developer of an ERP system, or a company that develops a component for an ERP system.
The companies that use the ERP system (or related components), are the tenant's customers. |
If this sounds familiar, please feel free to contact EasyUBL.
Developer support: easyubl@easyubl.eu If you are interested in working with EasyUBL, we will send you a Tenant key that gives you access to the EasyUBL API. We will also create a user for you, that gives you access to the Bookkeepers page as a Tenant administrator. Once you have received a Tenant key and a Tenant administrator account, you are considered a customer of EasyUBL. |
You can immediately receive UBL invoices using the Bookkeeper page. So you are up and running from day one.
We will invoice you 0.01 EUR for each document you send/receive. We know that development takes time and does not always go according to plan. Therefore, we will not stress you with demands to achieve a certain volume. If there has been no activity on your Tenant for 6 months, we will contact you and suggest that we close your Tenant. |
You can create a company administrator account for each of your customers. A company administrator can create users for the company they manage.
We invoice 10 eur per month for each user, except for your tenant administrator. The price you invoice your customer may vary depending on what other features you add. You will be able to use our invoice to form your own invoicing basis. We will invoice you from the very beginning, even if it may only be a few eur. These will probably be the first UBL invoices you receive, and will familiarize you with the receipt. It also gives you the opportunity to develop automatic invoicing for your customers, based on the traffic and users specification in our invoice. |
Create your own sandbox
You may start by creating your own company (the one that will receive invoices from EasyUBL) directly in the EasyUBL API. If you fill in the small json document under the "Company/Update" function and press "Execute", the company is created and you are ready to send/receive. Please note that only "real" companies can be created. You cannot therefore create fictitious companies with company numbers that are not registered.
The new company will immediately appear in the list of your Tenant's companies in the "Bookkeepers page". As soon as you have done this, we will send you a test invoice. This will appear in the document list. A company can send invoices to itself. You can therefore also immediately try sending your company an invoice directly from the EasyUBL API. Now you can see that the functions work. You then have to make the same thing happen from your application. This is of course much more difficult than our small example. It would be a good idea to start with an online meeting with EasyUBL, where we will show you examples of how it can be done. |
Your company will immediately receive UBL invoices, not only from EasyUBL. It would therefore be appropriate to have these loaded into the ERP system first. You can see the document (voucher) EasyUBL delivers under the Creditor/NextTransaction function. The task is to retrieve this document and deliver it to the ERP system's journal.
You can do this much more elegantly by using EasyUBL webhooks. The document delivered by our webhook is the same as the one retrieved with the API call. The document also contains information relating to goods transactions. You can skip these for now. Handling stock receipts in the ERP system is considerably more complicated than bookkeeping. The document you receive for accounting contains the invoice as XML, pdf and html. The accountant's site archives these documents for 3 months. If it is not possible to archive the documents in the ERP system, we can store them in EasyUBL (price?) |
Before you can send/receive, you must create a company
API/Company/AddUpdateCompany |
HttpClient myClient = new HttpClient();
myClient.DefaultRequestHeaders.Add("Authorization", ApiKey); string myUrl = String.Concat("https://EasyUBL.net/api/Company/Update/", CompanyId); string myCompanyJson = JsonConvert.SerializeObject(myCompany); var stringContent = new StringContent(myCompanyJson, UnicodeEncoding.UTF8, "application/json"); var response = await myClient.PostAsync(myUrl, stringContent); response.EnsureSuccessStatusCode(); if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync(); string sub = (string)JsonConvert.DeserializeObject(responseContent); CompanyId = Guid.Parse(sub); // save the company guid in your application } |
- |
public class companyEasyUBL { public string name { get; set; } public string cvr { get; set; } public string currency { get; set; } public string country { get; set; } public string? webhookUrl { get; set; } public addEndpoint defaultEndpoint { get; set; } public addAddress defaultAddress { get; set; } public addContact defaultContact { get; set; } public addPayment payment { get; set; } public bool? DoNotReceiveUBL { get; set; } = false; } public class addEndpoint { public string endpointType { get; set; } public string endpointIdentifier { get; set; } } public class addAddress { public string? name { get; set; } public string? streetName { get; set; } public string? additionalStreetName { get; set; } public string? buildingNumber { get; set; } public string? inhouseMail { get; set; } public string? department { get; set; } public string? attensionName { get; set; } public string? cityName { get; set; } public string? postalCode { get; set; } public string? countrySubentity { get; set; } public string? countryCode { get; set; } } public class addContact { public string roleCode { get; set; } public string name { get; set; } public string email { get; set; } public string sms { get; set; } } public class addPayment { public string bankname { get; set; } public string bankRegNo { get; set; } public string bankAccount { get; set; } public string bic { get; set; } public string iban { get; set; } public string CreditorIdentifier { get; set; } } |
The preferred way to send an invoice
Sending invoices and receiving notifications should be the easy way to handle an invoice. The possibilities depend entirely on the extent to which it is possible to make changes to the ERP system. The integration with EasyUBL is the easy part. Don't underestimate the importance of handling notifications. |
Invoices are sent with the feature /api/ SendDocuments/ Invoice/ {companyId} The function demands "companyId" as a parameter to identify the sender company address (the supplier). This ensures that no one sends invoices on your behalf through EasyUBL. This information is found in your database after calling AddUpdate (create companies). The function SendDocuments/Invoice" sends the invoice and returns the complete UBL document. |
HttpClient myClient = new HttpClient(); myClient.DefaultRequestHeaders.Add("Authorization",myTenantKey); string myUrl = String.Concat("https:// EasyUBL.net/api /SendDocuments/ Invoice/", companyId); string myInvoiceJson = JsonConvert.SerializeObject(myInvoice); var stringContent = new StringContent(myInvoiceJson, UnicodeEncoding.UTF8, "application/json"); var response = await myClient.PostAsync(myUrl, stringContent); response.EnsureSuccessStatusCode(); myXmlDocument = await response.Content.ReadAsStringAsync(); |
You should archive the complete UBL document in the database. This is the legal document the recipient receives. In the event of disputes, the complete UBL document is what must be referred to. Human readable versions formed on the fly like PDF, HTML etc. must be
considered "copies with special features" like being human readable, but they are not the legal document. That is solely the actual complete UBL document. Some recipients have special requirements for the content, that must be agreed with the invoice issuing company. For example, this could be a requisition number, specific contact persons, accounting codes, cost centers etc. If the recipient has an elaborate system, a message will be returned, if any of these informations are missing. If the recipient behaves correctly, this message will indicate, where in the UBL document this information must be placed. This means that you will be notified very quickly after sending a document, and you can then add any missing information, if that's the case, and resend it right away, not having to hunt down someone at the sender, who knows where the information should be found in the document. Furthermore, the UBL document is the legal document. In the event of disputes, this is what must be referred to. Human readable versions can be considered copies with special abilities that are formed on the fly. |
The document may be built in this way. This is only an example to illustrate the scope. Data is read from an SQL server and placed in the json document. |
SqlDataReader myr = Comm.ExecuteReader(); if (myr.Read()) { int AddressID = (int)myr["So_addressID"]; if (AddressID == 0) errCode = 1; int CreInvFactor = (int)myr["CreInvFactor"]; if (CreInvFactor == -1) myI.invoiceCreditnote = "Cre"; else myI.invoiceCreditnote = "Inv"; myI.id = new(myr["InvoiceNo"].ToString()); myI.documentCurrencyCode = myr["Currency"].ToString().ToUpper(); myI.issueDate = (myr["InvDate"].Equals(DBNull.Value) ? DateTime.Today : (DateTime)myr["InvDate"]); myI.dueDate = (myr["PayDate"].Equals(DBNull.Value) ? DateTime.Today : (DateTime)myr["PayDate"]); myI.accountingCost = myr["AccountingCost"].ToString(); myI.buyerReference = myr["requisition"].ToString(); long OrderNo; long.TryParse(myr["OrderNo"].ToString(), out OrderNo); myI.salesOrderID = OrderNo.ToString(); myI.note = string.Concat(myr["text_1"], " ", myr["text_2"]).Trim(); if (myr["ShipDate"].Equals(DBNull.Value)) myI.deliveryDate = myI.issueDate; else myI.deliveryDate = (DateTime)myr["ShipDate"]; int thisContId = myr["ContID"] == DBNull.Value ? 0 : (int)myr["ContID"]; myI.accountingCustomerParty = GetPartyInfo((int)myr["So_addressID"]); myI.accountingCustomerParty.Contact = GetContactInfo((int)myr["So_addressID"], thisContId); if (string.IsNullOrEmpty(myI.accountingCustomerParty.Contact.name)) { myI.accountingCustomerParty.Contact.name = myI.accountingCustomerParty.name; } myI.totalAmount = (decimal)myr["amount"]; myI.accountingCustomerParty.postalAddress = GetPostalAddress((int)myr["Sh_addressID"]); if ((int)myr["Sh_addressID"] != 0) myI.deliverAddress = GetPostalAddress((int)myr["Sh_addressID"]); myI.invoiceLines = GetLines(saleID); } return myI; |
It is a traditional mapping of the fields found in the local database for the JSON document describing the invoice. Enjoy the fact that it is significantly easier to map for this document than to the underlying XML document.
Feel free to use the source text for this application. If you turn to Easyubl support, we will be happy to help with advice and guidance. |