Overview
Upflow offers a robust public API that allows you to set up a data pipeline from an accounting source outside of our natively supported integrations.
The following guide will help ensure an optimal initial import of historical data into Upflow and subsequent live synchronization of up to date data.
________________________________________________________________________________________
Data Model Mapping
The Upflow data model contains the following entities:
-
Customer
-
Contact
-
Invoice
-
Credit Note
-
Payment
-
Refund
If your model contains entities that affect the customer balance but which are not present on this list (e.g. Adjustments, Journal Entries...) the solution is to map them on a payment or a refund.
________________________________________________________________________________________
API Usage
Sandbox Environment
You can develop and test your integration in our API sandbox: https://api.sandbox.upflow.io/v1/
Authentication
All requests must include the X-Api-Key
and X-Api-Secret
authentication headers with each request. These can be obtained by accessing the Settings Menu > API:
Initial Import
During the initial import, we recommend importing the data sequentially, that is, where you wait for a request to end before making the next one.
- If you want to parallelize the requests to increase the throughput, you should limit the number of concurrent requests to 5.
- Note: API is rate limited to 600 requests per minute and has a concurrency limit of 10.
- Note: API is rate limited to 600 requests per minute and has a concurrency limit of 10.
- For optimal performance, you should avoid importing two entities linked to the same customer at the same time.
Live synchronization
To implement the live synchronization, you’ll need to detect the changes that are made in the source and apply them in Upflow using the appropriate endpoint.
- Re-importing all the data from the source every day should be avoided as it’s not scalable.
Reliability recommendation
To ensure consistent reliability in the rare case of the API being down, we recommend to use retry failed request (connection error, 500 or 503) with an exponential backoff (e.g. retry after 1s, 2s, 4s, 8s...).
- You should not retry 40x errors which are not transient, except if you know precisely what you’re doing (e.g. overcome ordering issues).
Addressing Models using externalId
All models contain an externalId
field which can be used to store your own identifier in Upflow.
-
The
externalId
field should always contain the source system entity’s id and it should be unique and immutable.
If you opt for this type of integration, you can prefix ids with external:
in order to lookup Upflow models using your identifier.
-
- Examples:
-
GET https://api.upflow.io/v1/customers/12345
returns the customer withid = 12345
-
GET https://api.upflow.io/v1/customers/external:12345
returns the customer withexternalId = 12345
-
- Examples:
________________________________________________________________________________________
API Functions
Import
To ease the data import, our API provides a unique endpoint per entity to create or update.
These endpoints will have the following format:
POST https://api.upflow.io/v1/<entity_type>
{
"externalId": "...",
...
}
The externalId
field will allow you to detect if the entity has already been imported into Upflow.
If so, the entity will be updated; if not, a new entity will be created.
- Please ensure that your external id's are unique identifiers. Otherwise, entities could be removed accidentally.
Retrieve
Any entity imported in Upflow can be retrieved with its external id using the following type of endpoint:
GET https://api.upflow.io/v1/<entity_type>/external:<external_id>
Delete
In the same way you can retrieve an entity from Upflow, you can also delete an imported entity:
DELETE https://api.upflow.io/v1/<entity_type>/external:<external_id>
________________________________________________________________________________________
API Endpoints
Basic API documentation on all endpoints can be found here. Supplemental info pertinent to API integrators found below:
Import Customer
Refer to the Import Customer endpoint here.
Example:
POST https://api.upflow.io/v1/customers
{
"externalId": "1a2c3b",
"name": "Upflow SAS",
"address": {
"address": "25 Passage Dubail",
"zipcode": "75010",
"city": "Paris",
"country": "France"
},
"parent": {
"externalId": "1a2c3c"
},
"contacts": [
{
"firstName": "John",
"lastName": "Doe",
"phone": "+33678059778",
"email": "john@example.com",
"position": "ACCOUNTING",
"externalId": "1a2c3d",
"isMain": true
}
]
}
-
Parent-child relation
- Upflow supports single level parent-child relationships (a parent customer cannot have a parent). If you have multiple levels of hierarchy, you should link all the child customers to their root ancestor when importing them in Upflow.
- A parent-child relationship between two customers should be imported by referencing the parent customer from the child customer. Therefore, the parent customer should be imported before the child customers. Otherwise, a 400 error saying the parent customer does not exist will be returned.
- A parent-child relationship between two customers should be imported by referencing the parent customer from the child customer. Therefore, the parent customer should be imported before the child customers. Otherwise, a 400 error saying the parent customer does not exist will be returned.
- Upflow supports single level parent-child relationships (a parent customer cannot have a parent). If you have multiple levels of hierarchy, you should link all the child customers to their root ancestor when importing them in Upflow.
-
Contact List
- A list of contacts can be provided along with the customer details.
- If the
contacts
field is set, it should always contain the full list of contacts. Otherwise, the previously imported contacts which are not in the list anymore will be removed from Upflow.
- If the
contacts
field is not present in the body, the list of contacts will left as it is.- Note: The contact email is mandatory and must be unique.
- Note: The contact email is mandatory and must be unique.
-
Customer Contact relation
- The customer contact relation is a one-to-one relation. This means that a contact cannot be linked to multiple customers at the same time.
- However, if you have to assign the same contact to multiple customers, you can do so by providing the same
externalId
for the contact. Upflow will assign each customer’s contact a unique id to maintain unicity.
- The customer contact relation is a one-to-one relation. This means that a contact cannot be linked to multiple customers at the same time.
Notes:
-
- You can create customer contacts through this endpoint but the Contact Position (e.g. ACCOUNTING, PAYER, etc) must exist already in your organization.
- To create a new Contact Position, you can do so by accessing your Settings > Contact Management > under Positions > Add.
- For example, if your sandbox's language is English but your production organization's language is French then the same request that succeeds in the sandbox will fail in production since the positions have effectively different names.
- For example, if your sandbox's language is English but your production organization's language is French then the same request that succeeds in the sandbox will fail in production since the positions have effectively different names.
- To create a new Contact Position, you can do so by accessing your Settings > Contact Management > under Positions > Add.
- Dunning plans (workflows) cannot be imported OR created via the API. Only existing dunning plans can be linked to customers via API.
- You will not be able to create a custom field via the Import Customer endpoint.
- You can create customer contacts through this endpoint but the Contact Position (e.g. ACCOUNTING, PAYER, etc) must exist already in your organization.
List Customers
Refer to the List Customers endpoint here.
- Note: You can filter by custom field values through this endpoint through the following request structure:
<base_url>/v1/customers?customFieldData_<custom_field_id>.eq=<value>
-
- Example:
<https://api.sandbox.upflow.io/v1/customers?customFieldsData_1d234ee4-e6fd-45f1-b97e-2795d03208c1.eq=Huguenel%20Motorbikes%20Inc>
-
-
- You can fetch the custom field id through the List Custom Fields endpoint.
-
Pagination:
- There is a 1000 record per page limit on this endpoint.
Delete Customer
Refer to the Delete Customer endpoint here.
- Only empty customers (no invoice, no payment etc.) should be deleted.
Import Contacts
There are two ways to import contacts:
-
Import them along with the customer (
customer.contacts
field).- See Import Customer Section above.
- See Import Customer Section above.
-
Import them separately with the dedicated endpoints.
- Refer to the Create Customer Contacts endpoint here.
- Example:
-
POST https://api.upflow.io/v1/customers/external:123456/contacts
{
"firstName": "John",
"lastName": "Doe",
"phone": "+33678059778",
"email": "john@example.com",
"position": "ACCOUNTING",
"externalId": "1a2b3c",
"isMain": true
}
-
- Example:
- Refer to the Create Customer Contacts endpoint here.
Choose the solution which best fits your needs.
Import Invoice
Refer to the Import Invoice endpoint here.
Example:
POST https://api.upflow.io/v1/invoices
{
"customId": "INV123456",
"externalId": "54a65b4c32",
"issuedAt": "2015-05-05T12:30:00Z",
"dueDate": "2015-06-05T12:30:00Z",
"currency": "EUR",
"grossAmount": 1700,
"netAmount": 1500,
"customer":
{
"externalId": "1a2c3b"
}
}
Basic operations to Import data from your system ⇒ Upflow :
-
New invoice ⇒ Create / Import Invoice
-
Upload the invoice PDF ⇒ Upload Invoice PDF
-
With multipart/form-data:
To upload invoice PDFs, the recommended solution is to use the multipart/form-data format with the file field containing the file content.
-
With JSON body:
If for some reason, you’re not able to provide the file with the multipart/form-data format, you can also encode the file content in base64 and send it via a JSON field.
- See also How to update an invoice PDF via API
-
-
Deletion of an invoice ⇒ Delete Invoice
Basic operations to Retrieve data from Upflow :
-
Single invoice ⇒ Get Invoice
-
Multiple invoices ⇒ List Invoices
-
Pagination: There is a 500 record per page limit on this endpoint.
-
Import Payment
Refer to the Import Payment endpoint here.
-
The payment must be linked to a customer which can be referenced with its external id:
"customer": { "externalId": "12345" }
-
The payment can be linked to one or several invoices.
-
The applied amount must be specified.
"linkedInvoices": [
{ "amountLinked": "1000",
"invoice":
{ "externalId": "125643" }
}
] -
If the payment is refunded, the link must be specified from the refund object.
- You can also use Payments linked only to a customer to materialize a generic Journal Entry of type "Credit".
Import Credit Note
Refer to the Import Credit Note endpoint here.
- Like a payment, the credit note must be linked to a customer and, optionally, to one or several invoices.
- Import Credit Note PDF
- Refer to the Import Credit Note PDF import endpoint here.
- The process is the same as for importing invoice PDF's.
- Refer to the Import Credit Note PDF import endpoint here.
Import Refund
Refer to the Import Refund endpoint here.
The refund must be linked to a customer, and optionally to one or several payments or credit notes.
"linkedPayments": [
{ "amountLinked": "1000", "payment": { "externalId": "1234" } }
],
"linkedCreditNotes": [
{ "amountLinked": "2000", "creditNote": { "externalId": "4321" } }
],
- You can also use Refunds on a customer account to materialize a generic Journal Entry of type "Debit"
Additional Endpoints:
Create Customer Portal URL
Refer to the Create Customer Portal endpoint here and the dedicated Help Center article here.
- This endpoint is used to generate a portal URL for a customer. You can link this URL in your app, or embed it in an iframe to allow your users to access the customer portal from your app. To embed it in an iframe, you must specify the
frameAncestors
attribute in the request.
- The call to retrieve the portal URL must strictly be made from the backend (not the frontend) as it utilises the client’s API secret.
-
Note: There is no maximum to the
expiresIn
parameter. Our recommendation regarding the timeframe before expiration depends on the usage they need. The lowest is the best for better security because it decreases the risk of someone intercepting the token. So we recommend:
- One day for immediate usage.
- 25 days for cases of longer usage such as including the customer portal URL in an reminder that won't be opened immediately.
- One day for immediate usage.
Create Custom Fields
Refer to the Create Custom Field endpoint here.
Notes:
- For creating/listing custom fields, use
https://api.upflow.io/v1/custom_field
API endpoint, GET/POST.
- For linking custom fields to customers, use
https://api.upflow.io/v1/customer/
or usehttps://api.upflow.io/v1/customer/customerid
endpoint, POST/PUT.
- You will not be able to create a custom field via the Import Customer endpoint.
- Payment and Credit Note custom fields can be created through this endpoint using the "entityType": "CREDIT_NOTE” or “PAYMENT”.
Values must be manually assigned on the UI.
- You can create custom fields with DATATYPE: SELECT or MULTI_SELECT through this endpoint.
- The select values need not be specified on this request.
- Example Request Body:
- The select values need not be specified on this request.
{
"externalId": "123",
"label": "Select Custom Field",
"description": "custom field description",
"dataType": "SELECT",
"entityType": "CUSTOMER"
}
-
- The call should yield a 201 Created status code when successful.
The custom field should now appear under the Customers entity (or the entity you indicate on the request) in your Settings > Custom Fields page.
- Once the custom field is created, you will be able to use the Update Customer endpoint to both create the select value and assign that select value to the customer at the same time.
- Each time you use the API to input a new select value, a new selectable value is added to the dropdown for that custom field.
-
Important: Values are case-sensitive so for example "One" and "one" will create two separate select values for the field.
- You can also both create a select value and assign that select value to a customer at the same time when creating a customer using the Import Customer endpoint. (The only difference to the request is that this would be a POST request, the Upflow ID/external Id is omitted from the URL, and name & externalId of customer is required in the body in addition to the custom field array.)
- The call should yield a 201 Created status code when successful.
The formatting for the body of the PUT: Update Customer request is shown below:
- For SELECT custom field:
{
"customFields": [
{
"id": "12345",
"externalId": "678910",
"value":
{
"label": "One"
}
}
]
}
(Note: You can exclude either the custom field id or external id from the body but not both.)
- For MULTI_SELECT custom field:
{
"customFields": [
{
"id": "12345",
"externalId": "678910",
"value": [
{
"label": "One"
},
{
"label": "Two"
}]
}
]
}
(Note: You can exclude either the custom field id or external id from the body but not both.)
________________________________________________________________________________________
If you have any questions/concerns, please submit a Support Request at the top of this article!