Glossary
- Atlantic eBridge (AeB, eBridge) - an integration platform developed by Uni Micro Web;
- SoftRig - a headless accounting platform developed by Uni Micro;
- Uni Economy - an accounting system built on top of the SoftRig platform, owned by Uni Micro;
- DNB Regnskap - an accounting system built on top of the SoftRig platform, owned by DNB Bank ASA;
- Sparebank1 Regnskap - an accounting system built on top of the SoftRig platform, owned by SpareBank 1 Gruppen;
- Test-SoftRig - the SoftRig platform’s test-environment with its own “head“, used by the different integration partners for development and testing purposes, developed and owned by Uni Micro;
- OMS - Order Management System;
- IMS - Inventory Management System;
- POS - Point-Of-Sale software solution;
- External system (AeB connection, connection) - an external software that is integrated towards Atlantic eBridge;
- Sales channel - an external system that produces online orders (e.g. e-commerce, POS system, etc.);
- AeB company (AeB client) - a tenant in Atlantic eBridge;
- AeB user - a user account in Atlantic eBridge that can have access to 0..n AeB companies;
Overview
Atlantic eBridge is an integration platform that aims to automate different e-commerce business processes by connecting different digital sales channels to an accounting system, OMS (Order Management System), IMS (Inventory Management System) and other different support services.
There are 3 Atlantic eBridge environments:
Dev (nightly builds):
Test (beta channel):
Live (stable channel):
We suggest to support switching between the environments in sales channel integration configuration.
Atlantic eBridge API
Sales channels communicate with the Atlantic eBridge API in an asynchronous manner, by using GraphQL endpoints to send commands with data and subscribing to Atlantic eBridge webhooks to receive commands and events.
Connecting and authentication
Every new sales channel type has to be registered first in Atlantic eBridge as an external connection. For now, this can only be done by contacting Atlantic eBridge integration team. After the new connection is registered, it becomes available for activation in the company connections setup.
When the connection is activated on a company, Atlantic eBridge will generate a pair of ClientId and ClientSecret values that can be used to invoke eBridge API and validate incoming webhook requests.
Atlantic eBridge API endpoints
Atlantic eBridge API is implemented as GraphQL API. You can explore the API by using the online GraphQL tool https://graphiql-online.com/ . At the right side there is an interactive documentation section.
List of available Atlantic eBridge GaphQL endpoints:
- /webhook/graphql
- /order/graphql
- /product/graphql
Sales channels must include ClientId in X-EBridge-ClientID and ClientSecret in X-EBridge-ClientSecret http headers correspondingly while accessing Atlantic eBridge API endpoints.
Atlantic eBridge webhooks
Atlantic eBridge uses webhooks to notify external systems when an event happens.
To subscribe, unsubscribe and view existing subscriptions, use webhooks GraphQL API available at /webhook/graphql URL.
Sales channels can subscribe to Atlantic eBridge webhooks by sending the following request:
POST /webhook/graphql
mutation {
webhookSubscriptionCreate(webhookSubscription: WebHookSubscriptionInput!): WebhookSubscription
}
If the sales channel is already subscribed to a webhook topic with the same URL, then no new subscription is created and mutation will return the ID of the existing subscription. However, it is (currently) possible to have multiple URLs subscribed to the same topic for a single sales channel.
To unsubscribe from Atlantic eBridge webhook, send the following request:
POST /webhook/graphql
mutation { webhookSubscriptionDelete(webhookSubscriptionId: string!): Boolean}
Verify the webhook
Before you respond to a webhook, you need to verify that the webhook was sent from Atlantic eBridge. You can verify the webhook by calculating a digital signature.
Each webhook request includes a X-EBridge-Hmac-SHA256 header, which is generated using the API secret key along with the data sent in the request. Below is a c# example of the webhook verification:
string clientSecret = "[YOUR_CLIENT_SECRET_VALUE]"; // replace [YOUR_CLIENT_SECRET_VALUE] with your X-EBridge-ClientSecret value
byte[] key = Convert.FromBase64String(clientSecret);
string signature = Request.Headers["X-EBridge-Hmac-SHA256"];
using var reader = new System.IO.StreamReader(Request.Body);
string body = reader.ReadToEnd();
byte[] encodedData = Encoding.UTF8.GetBytes(body);
using var hmac = new HMACSHA256(key);
bool isVerified = signature.Equals(Convert.ToBase64String(hmac.ComputeHash(encodedData));
return isVerified;
Respond to the webhook
Your webhook acknowledges that it received data by sending a 200 OK response. Subscriber should respond to webhooks as soon as possible, but only after it has processed the message or queued it locally to process later.
Response with status code 400 Bad Request means that the webhook cannot be processed and Atlantic eBridge will not retry sending it again. All other response status codes, including 3XX redirects will be retried later.
Please note that Atlantic eBridge doesn't follow redirects for webhook notifications and considers them to be an error response.
Webhook retries
Atlantic eBridge waits for 20 seconds for a response to each request to a webhook. If there's no response, or an error is returned (except 400 Bad Request), then Atlantic eBridge retries the delivery 30 times over the next 25 hours with exponential backoff to make sure events are delivered.
Workflows
A sales channel integration consists of 2 main parts:
- Order workflows;
- Product and inventory workflows;
Order workflows
Atlantic eBridge automatically handles accounting for online orders registered and processed in sales channel. This includes registration of invoices and credit notes in accounting system, bookkeeping of payouts and other related flows.
For these purposes, the following order workflows have to be implemented by the sales channel.
Order registered in sales channel
When a new order is registered in sales channel, execute the following GraphQL mutation:
POST /order/graphql
mutation {
notifyOrderCreated(orderId: String!, order: OrderInput!): Boolean
}
Order changed in sales channel
When an order is changed in sales channel (for example, address or order lines content have been changed), execute the following GraphQL mutation:
POST /order/graphql
mutation {
notifyOrderUpdateComplete(orderId: String!, operationId: String, order: OrderInput, errorMessage: String): Boolean
}
Please note, that different order state changes (payment, delivery, order statuses) have their own notification endpoints and should not trigger order changed notifications.
Order cancelled in sales channel
When an order is cancelled in sales channel, execute the following GraphQL mutation:
POST /order/graphql
mutation {
notifyOrderCancelComplete(orderId: String!, operationId: String, errorMessage: String): Boolean
}
Order payment captured in sales channel
When an order payment is captured (partially or entirely) in sales channel, execute the following GraphQL mutation:
POST /order/graphql
mutation { notifyOrderPaymentComplete(orderPaymentCompleteInput: OrderPaymentCompleteInput!): Boolean}
Order payment credited in sales channel
When an order payment is credited (partially or entirely) in sales channel, execute the following GraphQL mutation:
POST /order/graphql
mutation { notifyOrderCreditComplete(orderCreditCompleteInput: OrderPaymentCompleteInput!): Boolean}
OMS-related order flows
Atlantic eBridge supports integrations towards OMS (Order Management System) and IMS (Inventory Management System), allowing customers to work with all their online orders from one single place.
For these purposes, the following additonal order workflows have to be implemented by the sales channel.
Order fulfilling in OMS (“Order.Payment.Complete” webhook)
When an order is ready to be fulfilled (partially or entirely), Atlantic eBridge verifies if the fulfillment can be processed (e.g. order lines are ready to be fulfilled and payment reservation is still available). Atlantic eBridge triggers the Order.Payment.Complete webhook to signal to the corresponding sales channel to try capturing the payment.
Order.Payment.Complete payload scheme
{ operationId: string, // Value used to correlate this request with the result. orderId: { // Represents a set of values that uniquely identify an order in external system. systemType: string, // Type of external system (e.g. "Shopify", "MooCommerce", etc). systemId: string, // ID of external system (e.g. "MooCommerce_shop_id"). orderId: string // ID of the order in external system. }, orderLines: [{ // Optional list of order lines on which payment operation should be performed. Null or empty array means all order lines for which given operation is possible. id: string, // Order line ID quantity: decimal // Order line product quantity }]}
Sales channel must subscribe to this webhook and try capturing the payment for the requested order lines when triggered. In case of non-prepaid orders, sales channel only have to to validate the request and split order lines if needed.
The result of this operation must be reported back to the Atlantic eBridge GraphQL endpoint as described in the “Order payment captured in sales channel“ workflow. Please note, that if there was an operationId value in the webhook payload, this value must be included to the reporting request payload as well.
After OMS receives successful operation result from Atlantic eBridge, it continues the fulfillment process on their side.
Order fulfilled in OMS (“Order.Fulfillment.Create.Completed” webhook)
When an order is fulfilled (partially or entirely) in OMS, Atlantic eBridge triggers the Order.Fulfillment.Create.Completed webhook to signal to the corresponding sales channel that the order has been fulfilled.
Order.Fulfillment.Create.Completed payload scheme
{ operationId: string, // ID of the operation, if any, that caused this change. orderId: { // Represents a set of values that uniquely identify an order in external system. systemType: string, // Type of external system (e.g. "Shopify", "MooCommerce", etc). systemId: string, // ID of external system (e.g. "MooCommerce_shop_id"). orderId: string // ID of the order in external system. }, fulfillment: { // Order fulfillment. id: { // Represents a set of values that uniquely identify an order fulfillment in external system. systemType: string, // Type of external system (e.g. "Shopify", "MooCommerce", etc). systemId: string, // ID of external system (e.g. "MooCommerce_shop_id"). fulfillmentId: string // ID of the order fulfillment in external system. }, trackingInfo: { // Optional tracking info for the order fulfillment. company: string, // The name of the tracking company. number: string, // The tracking number of the fulfillment. url: string // The URL to track the fulfillment. }, items: [{ // List of order lines included in the fulfillment. orderLineId: string, // Order line ID in external system where order originates from. quantity: decimal // Number of line items in the fulfillment. }] }, errorMessage: string // Message describing failure reason if requested operation could not be executed.}
Sales channel can use this information to update shipping statuses and tracking information in order lines, if needed.
Order changing in OMS (“Order.Update” webhook)
Before saving changes to an order, OMS needs to ensure that these changes can be processed in the corresponding sales channel (e.g. order is still available and payment reservation allows to perform the requested changes). Atlantic eBridge triggers the Order.Update webhook to signal to the corresponding sales channel to try changing the order.
Order.Update payload scheme
{ operationId: string, // Value used to correlate this request with the result. orderId: { // Represents a set of values that uniquely identify an order in external system. systemType: string, // Type of external system (e.g. "Shopify", "MooCommerce", etc). systemId: string, // ID of external system (e.g. "MooCommerce_shop_id"). orderId: string // ID of the order in external system. }, billingAddress: { // Invoice address of the order. countryCode: string, // The invoice country code in ISO 3166 alpha-2 format. Eg: NO, GB, SE, DE, US, etc. postalCode: string, // The invoice postal code. city: string, // The invoice city. address1: string, // The invoice primary address line. address2: string, // An additional invoice address line. name: string, // The full name of the buyer. phone: string // The invoice phone number. }, shippingAddress: { // Shipping address of the order. countryCode: string, // The shipping country code in ISO 3166 alpha-2 format. Eg: NO, GB, SE, DE, US, etc. postalCode: string, // The shipping postal code. city: string, // The shipping city. address1: string, // The shipping primary address line. address2: string, // An additional shipping address line. name: string, // The full name of the customer. phone: string // The shipping phone number. }, orderNote: string, // Order note. orderLines: [{ // Order lines. action: enum, // Order line action. Possible values: Create, Update, Delete. orderLine: { // Order line parameters. Id: string, // Order line ID in external system where order originates from. splitFromId: string, // ID of the line this one has been split from. parentLineId: string, // ID of parent order line. sku: string, // Order line's product SKU. gtin: long, // Order line's product GTIN (Global Trade Item Number). name: string, // Order line's product name. unit: string, // Measurement unit of product quantity. discountPercent: decimal, // Applied discount percent (value between 0 and 100). discountAmount: decimal, // Total discounted amount. vatCode: string, // VAT code. vatPercent: decimal, // VAT percent (value between 0 and 100). quantity: decimal, // Quantity of product in line measured in units. sumTotalInclVat: decimal, // Total order line sell price, including VAT. totalVat: decimal, // Total order line VAT amount. currencyCode: string, // Three-letter ISO currency code, e.g. NOK, USD, EUR, etc. exchangeRate: decimal, // Currency exchange rate at the moment of the order payment authorization. lineType: enum, // Order line type. Possible values: Product, GroupingProduct, Expenses, TextLine, Fee, Discount paymentStatus: enum, // Order line payment status. Possible values: None, Authorized, Captured, Credited, Cancelled, AuthorizationExpired invoiceStatus: enum // Order line invoice status (accounting-wise). Possible values: None, Invoiced, Credited } }]}
Sales channel must subscribe to this webhook and try applying the requested changes to the order when triggered. The result of this operation must be reported back to the Atlantic eBridge GraphQL endpoint as described in the “Order changed in sales channel“ workflow. Please note, that if there was an operationId value in the webhook payload, this value must be included to the reporting request payload as well.
Order cancelled in OMS (Order.Cancel webhook)
When an order is cancelled in OMS, Atlantic eBridge triggers the Order.Cancel webhook to signal to the corresponding sales channel that the order has to be cancelled. The sales channel is expected to cancel the order, refund the payment if needed, and then invoke eBridge API to notify about success or failure.
Order.Cancel payload scheme
{ operationId: string, // Value used to correlate this request with the result. orderId: { // Represents a set of values that uniquely identify an order in external system. systemType: string, // Type of external system (e.g. "Shopify", "MooCommerce", etc). systemId: string, // ID of external system (e.g. "MooCommerce_shop_id"). orderId: string // ID of the order in external system. }}
Order payment refunded in OMS/Accounting system (“Order.Payment.Refund” webhook)
When an order payment is refunded in OMS or accounting system, Atlantic eBridge triggers the Order.Payment.Refund webhook to signal to the corresponding sales channel about this. The sales channel is expected to credit the payment (in case of pre-paid orders) and then notify Atlantic eBridge about success or failure, as described in the “Order payment credited in sales channel“ workflow.
Order.Payment.Refund payload scheme
{ operationId: string, // Value used to correlate this request with the result. orderId: { // Represents a set of values that uniquely identify an order in external system. systemType: string, // Type of external system (e.g. "Shopify", "MooCommerce", etc). systemId: string, // ID of external system (e.g. "MooCommerce_shop_id"). orderId: string // ID of the order in external system. }, orderLines: [{ // Optional list of order lines on which payment operation should be performed. Null or empty array means all order lines for which given operation is possible. id: string, // Order line ID quantity: decimal // Order line product quantity }]}
Product and inventory workflows
Product sync can help customers to keep their products registry consistent and up to date among different connected systems.
When a product is created, updated or deleted in one connected system, Atlantic eBridge distributes the changes among all enabled systems, according to the configuration.
The following product data is supported in Atlantic eBridge V1:
- SKU (required);
- Product name;
- VAT code;
- Unit;
- Stock quantity in one or multiple tracked IMS warehouses;
- Product price excl. VAT (single price);
SKU is considered the unique identifier of a product across different external systems.
Products created or updated in some other system (“ProductSync.Products.Updated” webhook)
When products are changed (created or updated) in some other system, Atlantic eBridge triggers the ProductSync.Products.Updated webhook to signal to the sales channel about it.
ProductSync.Products.Updated payload scheme
{ products: [{ sku: string, // Product unique SKU string value. name: string, // Product name. vatCode: string, // Product VAT code. unit: string, // Product measurement unit (pcs, kg, etc). priceExclVat: decimal, // Product price without VAT. stocks: [{ // Product stock availability in different warehouses. warehouseId: string, // Product stock IMS-warehouse ID. warehouseName: string, // Product stock IMS-warehouse name. quantity: decimal // Available product quantity in stock. }] }], reason: string // Optional reason of the changes.}
Please note, that the product sync in Atlantic eBridge supports partial product update semantics. It means that if the value was not updated in scope of the currently triggered event, the corresponding product field will have null value and should be ignored by the receiver. For example, if only price has been updated, the webhook payload will look like the following:
{ products: [{ sku: "some-sku-value", // Always has a value because it is the product identifier name: null, // Didn't change, ignore. vatCode: null, // Didn't change, ignore. unit: null, // Didn't change, ignore. priceExclVat: 123.45, // ! New value stocks: null // Didn't change, ignore. }], reason: "Price adjustments"}
To clear (empty, remove) some fields' values, a default type’s value is being used. E.g. '' (empty string) for the string fields, 0.00 for decimals, etc.
Products deleted/deactivated in some other system (“ProductSync.Products.Deleted” webhook)
When products are deleted (or deactivated/archived) in some other system, Atlantic eBridge triggers the ProductSync.Products.Deleted webhook to signal to the sales channel about it. The webhook's payload will contain an array of products with only SKU values:
ProductSync.Products.Deleted payload scheme
{ products: [{ sku: string, // Product unique SKU string value. }], reason: string // Optional reason of the deletion.}
Products created or updated in sales channel
When products are changed (created or updated) in sales channel, execute the following GraphQL mutation:
POST /product/graphql
mutation { notifyProductsUpdated(products: [ProductUpdatedInput]!, reason: String): Boolean!}
Products deleted/deactivated in sales channel
When products are deleted (or deactivated/archived) in sales channel, execute the following GraphQL mutation:
POST /product/graphql
mutation { notifyProductsDeleted(products: [ProductDeletedInput]!, reason: String): Boolean!}
Inventory workflows
Inventory (stock) is the quantity of a particular product that is available for sale. Inventory tracking can help customers avoid selling products that have run out of stock by distributing inventory changes from IMS to a sales channel.
IMS is the master source for all inventory changes. Any inventory changes made directly in sales channels will be ignored and will eventually be overridden by the inventory data from IMS.
All inventory changes are distributed as a part of the ProductSync.Products.Updated webhooks.