This example shows how your own iOS app (for example a WMS app) can open a Flux flow on the same iPhone, let the operator capture data (dimensions, photos, barcodes, weights, answers), and get the captured data back. No REST API is needed: the two apps talk to each other through links.
Flux was formerly called Dimmy. This integration is available on iOS only; Android is not supported yet.
- Requirements
- Quick start
- The link contract
- Receiving the result in your app
- Reading the data
- Known limits
- How it works
- Upgrading from the 2024 version
- Flux for iOS or later, installed on the same iPhone as your app.
- An operator logged into Flux on that iPhone.
- The name of the flow to run, built in the Flux web app. To go straight to measuring, make a flow with just one dimensioning step.
- Xcode 26 to build this example.
- Open
FluxIntegrationExample.xcodeprojin Xcode. Under Signing & Capabilities, pick your own team (and change the bundle id if Xcode asks). - Run the app on an iPhone that has Flux installed and logged in. The simulator cannot run Flux.
- Type your flow's name exactly as in the web app, optionally type a barcode, and tap Start scan in Flux. Run the flow in Flux; when you finish it, Flux switches back to the example and shows the result.
To use this in your own app, copy FluxLink.swift into it. It has no dependencies and does all the encoding for you. ContentView.swift shows how to call it.
Your app opens this link with UIApplication.shared.open(_:) (or SwiftUI's openURL). iOS hands it straight to Flux.
https://flux.api.optioryx.com/open?flowName=<flow name>&callback=<your URL>&code=<barcode>
| Parameter | Required | Meaning |
|---|---|---|
flowName |
yes | The name of the flow to run, exactly as in the Flux web app (upper and lower case matter). |
callback |
no | The URL Flux opens when it is done, as a normal URL in the query (percent-encoded, as every URL library does for you). Without it, the flow ends on Flux's own end screen and your app gets nothing back. |
code |
no | A barcode your app already knows, for example the order or SKU being measured. Flux stores it on the captured item so you can find the item later in the Flux web app and API. It does not skip or fill in a barcode step of the flow. |
FluxLink.openURL(flowName:callback:code:) builds this link for you.
Flux opens your callback URL with these query parameters added. Any query your callback already has is kept, so you can put your own context in it (for example myapp://flux-result?order=4711).
| Outcome | Parameters added |
|---|---|
| The operator finished the flow | status=completed&response=<data> |
| The operator left the flow without finishing it | status=cancelled |
| The flow could not start | status=error&error=<reason> |
Error reasons:
error |
Meaning |
|---|---|
invalid_request |
The link has no flowName. (If callback itself is not a valid URL, Flux cannot answer at all.) |
not_logged_in |
Nobody is logged into Flux on this iPhone. Ask the operator to log in and try again. |
flow_unavailable |
Flux does not know this flow: a typo in the name, a flow of another account, a flow with no steps, or a flow that needs a newer Flux version. |
response is the captured item as JSON, encoded as base64url (Base64 with - and _ instead of + and /, and no = padding, so it survives inside a URL unchanged). FluxLink.Result(url:) decodes it:
.onOpenURL { url in
switch FluxLink.Result(url: url) {
case .completed(let json): handle(json) // the captured item
case .cancelled: showCancelled()
case .error(let reason): showError(reason) // e.g. "not_logged_in"
case nil: break // not a Flux callback
}
}Your app needs a URL that iOS opens in your app. There are two ways.
A custom URL scheme (what this example does). Register a scheme in your app's Info.plist under CFBundleURLTypes (see Info.plist, which registers fluxexample) and pass a callback like fluxexample://result. Handle it with .onOpenURL in SwiftUI, or scene(_:openURLContexts:) in a UIKit scene delegate. It needs no server, but any app can register the same scheme, so pick a name that is unique to you.
A universal link (recommended for production). A normal https:// URL on a domain you own, which iOS opens in your app. It cannot be claimed by another app, but needs an apple-app-site-association file on your domain and the Associated Domains capability in your app. See Apple's guide: Supporting universal links in your app. Handle it with .onOpenURL in SwiftUI, or scene(_:continue:) in UIKit.
response holds the captured item in Flux's mobile format: one list per kind of step (dimensioning, photographing, barcodeScanning, weighing, customInputs, and so on), each entry tagged with the flowStepId of the step that produced it, plus startedAt and endedAt. Print it once for your flow (the example shows it on screen) and pick the fields you need.
FluxLink.dimensions(in:) shows how to read the first measured box:
if let box = FluxLink.dimensions(in: json) {
print(box.width, box.height, box.depth, box.unit)
}Good to know:
- Photos are links, not images. They may still be uploading when your app gets the result.
- The item is also uploaded to Flux as usual, so it appears in the Flux web app and API (and any webhooks you set up). The result does not include the item's id: to find the stored item later, search for the
codeyou passed.
- Renaming a flow in the web app breaks every link that uses its old name. Give integration flows a name you will keep.
- If two flows have the same name, Flux opens one of them. Keep integration flow names unique.
- Photos may still be uploading when the result arrives.
- Signatures are included as image data, which makes the result URL large.
- If the operator pauses a flow that your app started, your app gets no result for it.
- If a second link arrives while a flow started by a link is still open, the first flow is dropped and its app gets no result.
- iOS only.
sequenceDiagram
participant App as Your app
participant Flux as Flux iOS
participant API as Flux backend
App->>Flux: https://flux.api.optioryx.com/open?flowName=…&callback=…&code=…
Note over Flux: the operator runs the flow
Flux-->>API: uploads the item (in the background)
Flux->>App: callback?status=completed&response=<base64url JSON>
The https://flux.api.optioryx.com/open link is a universal link: Flux has claimed that address with Apple, so iOS opens Flux directly instead of the browser.
The 2024 version of this example used an older link format that current Flux versions no longer accept.
| 2024 | Now |
|---|---|
https://dimmy.api.optioryx.com/open |
https://flux.api.optioryx.com/open |
flow=<flow name>, or flow=default |
flowName=<flow name> (no default) |
callback Base64-encoded |
callback as a normal (percent-encoded) URL |
Only a response on success; nothing on cancel or error |
Always a status; response on success |
response in standard Base64 |
response in base64url |
