Build a Dynamics 365 F&O connector
If your company runs Dynamics 365 Finance and Operations, the connector is an extension in your model: a few tables, a client class, and batch jobs. Most partners already have this skeleton from another integration — a parameters form, an HTTP client with retry rules, staging tables, an execution log. Pointing it at Slflo changes the mappings and contracts, not the skeleton. This page lists each piece and what it does against Slflo.
Read the pull connector and master data guides first: they show the same flow with code that runs.
The pieces
Section titled “The pieces”| Piece in your extension | Against Slflo |
|---|---|
| Parameters table and form | Base URL https://api.slflo.com/api/integration/v1; the token, stored encrypted; page size (100); your throttle; the last version staged per stream and the last seq per document stream; an on/off switch per flow. |
API client class (a .NET HttpClient wrapper called from X++) |
Stop on 401 and alert (Slflo never blocks an IP for 401s); wait Retry-After on 429; back off on 500, 502, 503, 504 and timeouts; send an Idempotency-Key on every POST/PUT/DELETE, retries included. See retries. |
| Throttle | Just under rate_limit_per_minute from GET /me (120 by default). |
| Data contracts | Generated or hand-written from openapi-v1.json: OrderDto, OrderLineDto, RefDto, TotalsDto, InvoiceDto, PaymentDto, ReturnDto. Ignore fields you don’t know — new ones may be added to v1. |
| Staging tables | Header and lines, with a unique index on (Slflo id, version, line number) and a status field. |
| Batch jobs (SysOperation) | One per flow — orders, invoices, payments, returns, master data — on a recurrence, each writing to your execution log with Slflo’s request_id for every failed call. |
Orders → sales orders
Section titled “Orders → sales orders”- Pull
GET /orders?filter[status]=ERP_PENDING&filter[version_after]=<last staged version>&per_page=100, followingmeta.next_version_afteruntilhas_moreis false. Customer, branch, rep, product and unit come inline with both keys — no second call to look them up. - Stage every line under the unique index. A duplicate insert is not an error; skip it.
- Create one sales order per Slflo order. Put the Slflo order
idin the sales order’s customer reference (CustomersOrderReferenceon the sales order header entity), and search for it before creating. A job that died after creating finds its own sales order.- Customer account:
customer.external_ref. Delivery address:branch.external_ref, which readsACCOUNT/BRANCH. - Lines:
product.external_refis your item number,unit.external_refyour unit symbol,quantity,unit_price,discount;is_free_goodslines at zero price. - Prices and VAT: the rep quoted the customer
unit_priceand the VAT intax[]. Fix the line price to it rather than letting trade agreements re-price, and map the taxcode(VAT) to your sales tax groups.
- Customer account:
- Ack
POST /orders/{id}/ack, ACCEPTED with the sales order number asexternal_ref, or REJECTED with areason_codeand the infolog text asmessage(the office reads it). Many at once:POST /ackswith"entity": "order".
A refused order the office fixes comes back at a higher version through the same pull; see the refusal path.
Payments → customer payment journal
Section titled “Payments → customer payment journal”- Read
GET /payments?filter[seq_after]=<last receipt seq>— each receipt once, in issue order — or by version. - One journal line per payment: account type Customer, account
customer.external_ref, creditamount, datecollection_date. Mapmethod(CASH,CHEQUE,TRANSFER,INSTAPAY,WALLET, fromGET /reference/payment-methods) to your methods of payment; achequecarries bank, number and due date for post-dated cheques. - Settle against the invoices in
allocations— each names the invoice with both keys; what’s left ison_account. - Ack with the journal number. A payment reversed or a cheque bounced later is pending
again (
filter[ack]=pending) with areversal: reverse the journal and ack again. See invoices by seq.
Returns → return orders or credit notes
Section titled “Returns → return orders or credit notes”- Read
GET /returns?filter[seq_after]=<last credit note seq>; a return gets itsseqwhen it is credited (credit_note_number). - Each line points at the original invoice line (
invoicewith both keys,invoice_line_number); mapreason(fromGET /reference/return-reasons) to your return reason codes, and create a return order (RMA) or a credit note as your process books returns. - Ack with its number.
Invoices Slflo issued
Section titled “Invoices Slflo issued”Slflo issues an invoice for what it delivers: every van sale, at the shop, and any order the
office delivers in Slflo. If you don’t invoice those sales in Dynamics yourself, read GET /invoices?filter[seq_after]=… and book them — as your
accountant decides, for example as free text invoices — then ack with your voucher. The counter
has no gaps, so you can prove you hold every invoice.
Master data out
Section titled “Master data out”| Slflo | From Dynamics 365 | Call |
|---|---|---|
| Customer | Customer account (AccountNum), name, credit limit, blocked, customer price group |
PUT /customers/{AccountNum} |
| Branch | The customer’s delivery addresses | PUT /customers/{AccountNum}/branches/{ref} |
| Unit | Unit symbol | PUT /units/{Symbol} or POST /batch/units |
| Product | Item number, name, inventory unit, active | PUT /products/{ItemId} or POST /batch/products |
| Sellable units | Unit conversions to the inventory unit | PUT /products/{ItemId}/units |
| Price list | Customer price group | PUT /price-lists/{PriceGroup} |
| Prices | Sales trade agreements for the group, resolved to one price per item, unit and from-date | PUT /price-lists/{PriceGroup}/prices (≤ 500 rows, several merge calls when more) |
| Balance | The customer’s open balance, and when it was taken | PUT /customers/{AccountNum}/balance or POST /batch/balances |
There is no id to store: you push by your own keys. Keep a hash of each payload you sent
(MD5 or SHA-256 of the JSON) in a small table and skip the call when it hasn’t changed; Slflo
answers unchanged anyway, but skipping saves the request. Send the record’s modified time as
source_version so two jobs racing can’t roll a record back.
Mapping tables
Section titled “Mapping tables”Fetch Slflo’s code lists once and map them in small tables of your own:
GET /reference/payment-methods, return-reasons, units, warehouses, tax-codes. Each item
has code, a name in English and Arabic, and — for the company’s own lists — your key beside ours.
The order of work
Section titled “The order of work”- Parameters: the base URL and a sandbox token (
sfi_live_…); check it withGET /me. - Map the code lists.
- Master data out: units, price groups, items, prices, customers, balances — by your keys, with the payload-hash skip.
- Documents in: orders, then payments, returns and invoices — pull, stage, create with find-before-create, ack.
- Run the go-live checklist against the sandbox, then switch the parameters to a live token.

