A connection is one endpoint a vendor exposes to you — a host, a port, a username and a password. It is the door. What comes through the door (a catalog file, an inventory file) is a feed, and several feeds can run over the same connection. You enter the credentials once, on the connection, and rotate them once no matter how many feeds use them.
Where connections live
Go to Purchasing → Vendors, open the vendor, and choose the Integration tab. Scroll past the Products and Inventory panels — those hold the feeds — to the Connections panel at the bottom.
Each connection shows as a card with its label, a transport badge, and the endpoint summary: host:port and the username. If no password has been saved yet, the card shows a red No password set badge.
📷 Screenshot: The Connections panel on a vendor’s Integration tab, showing one connection card with its label, the SFTP badge, the
host:portand username line, and the “Edit connection” / “Delete” actions on the right. (placeholder — replace with/docs-images/vendors/vendor-connections-panel.png)
Connections vs. feeds
This is the distinction that makes everything else make sense.
| Connection | Feed | |
|---|---|---|
| Answers | How do we reach this vendor? | Which files, and what’s in them? |
| Holds | Transport, host, port, username, password | Directory, filename pattern, delimiter, column mappings, schedule |
| Lives under | The Connections panel | The Products and Inventory panels |
| How many | One per endpoint | As many as the vendor sends you — including several of the same type |
A vendor that drops a nightly catalog and an hourly inventory file on the same server needs one connection and two feeds. Add a second connection only when the vendor genuinely uses a separate endpoint — a different host, or a different login for a different data type.
✅ A connection can carry as many feeds as you need, including more than one of the same type. A vendor that ships an item-master file and a separate long-form description file, or a product sheet and an independent MAP price sheet, gets one product feed per drop — same connection, different directory, pattern, column map and schedule. The same is true of inventory: several inventory feeds can run over one endpoint. There is no “one product feed per vendor” or “one inventory feed per vendor” limit, and there is never a reason to create a duplicate vendor record to work around one.
ℹ️ Note: Spreadsheet-upload feeds have no connection at all. You hand ILLUMA the file, so there is nothing to dial. Only feeds with SFTP delivery reference a connection.
Transport
The Transport dropdown currently offers one option: SFTP. The form’s own hint says it plainly: FTPS, API and EDI transports are planned; SFTP is what runs today.
The field exists as a dropdown rather than a fixed label because a real vendor exposes more than one kind of endpoint — files over SFTP here, a different protocol there — and the record should be able to say which is which when those paths are built. Today it cannot be set to anything else: the dropdown lists only SFTP, and the save is rejected outright if some other value reaches it. Both readers guard the same line anyway, which is why you may see “Reading files over … isn’t supported yet” on a peek or “transport … has no delivery path yet” on a feed row — that is a connection on an unbuilt transport, and the fix is to use SFTP.
⚠️ Warning: The PO Submission Method at the top of the Integration tab is a separate setting and a separate direction. It controls how purchase orders go out to the vendor. Connections control how catalog and inventory files come in. Setting one does nothing to the other — a vendor can pull files over SFTP while its POs go out by email, and neither setting is evidence about the other.
ℹ️ Note: The two directions have different coverage, which is worth knowing before you go looking for a problem that isn’t there. On the outbound side, Email, Freshdesk and None all deliver a purchase order today — None is a real, implemented path that sends a plain HTML purchase-order email to the vendor’s drop-ship address, not a misconfiguration. EDI, API, FTP and portal submission are the outbound methods with no delivery path yet; the Integration tab says so on the panel itself. On the inbound side, SFTP is the transport that runs.
What to collect from the vendor
Before you open the form, get these from the vendor’s EDI or B2B team:
Host sftp.vendor.com (hostname only — no sftp:// and no path)
Port 22 (many B2B endpoints are NOT on 22)
Username YOURACCOUNT
Password ••••••••
Directory /outbound (needed for the feed, not the connection)
Two things worth asking about explicitly:
- The port. Vendor B2B gateways frequently sit on a non-standard port — Ace’s B2B SFTP, for example, listens on 10022, not 22. A wrong port looks exactly like a firewall problem.
- Whether they filter by IP. Some vendors only accept connections from addresses they have allowlisted. If they do, tell them ILLUMA connects from our platform network and ask what they need.
Add a connection
- Open the Connections panel — Purchasing → Vendors, open the vendor, Integration tab, scroll to Connections.
- Click “+ Add Connection” — the Add Connection modal opens.
- Give it a label — optional but recommended, e.g.
Ace B2B SFTP. The label is what you’ll see on the feed’s Delivery line and in the “Add Feed” picker. With no label, the host is shown instead. - Leave Transport on SFTP — it’s the only delivery path that runs today.
- Enter the host — the hostname only. No
sftp://, no trailing path, nouser@prefix. The form rejects all three. - Enter the port — defaults to
22. Change it if the vendor gave you a different one. - Enter the username and password — a password is required to create a connection. There is no SSH key option today.
- Click “Create Connection” — the card appears in the panel and the password is encrypted before it is stored.
📷 Screenshot: The Add Connection modal with Label, Transport (SFTP), Host and Port side by side, Username and Password, and the “Stored encrypted. Never displayed again.” hint under the password field. (placeholder — replace with
/docs-images/vendors/vendor-connections-add-modal.png)
💡 Tip: If you click + Add Feed on a vendor that has no connection yet, ILLUMA tells you “Add the SFTP connection first — the feed form opens right after” and opens this modal for you. Finish it and the feed form continues on its own.
Field reference
| Field | Required | Rules |
|---|---|---|
| Label | No | Up to 255 characters. Falls back to the host wherever it’s displayed. |
| Transport | Yes | SFTP only today. |
| Host | Yes | Hostname or public IP. Must be fully qualified (must contain a dot). No scheme, path, spaces, @ or backslashes. Up to 253 characters. |
| Port | No | Whole number, 1–65535. Defaults to 22 when left blank. |
| Username | Yes | Up to 255 characters. |
| Password | Yes on create | Stored encrypted and never shown again. On edit, leave blank to keep the current one. |
ℹ️ Note: A connection saved without a password is not a working connection. The Add Connection form refuses to submit without one, and if a credential-less record does exist — an older row, say — it announces itself with the red No password set badge, the peek answers “This connection has no password set yet”, and the poller stops its feeds with “connection has no credentials — set them on the vendor page.”
Hosts ILLUMA will not accept
A connection host is something our servers dial out to, so it has to point somewhere public. These are rejected at save time with a plain-language error:
| Rejected | Examples |
|---|---|
| A single-label name | sftpserver, vendorbox — “isn’t a full hostname” |
| Anything with a scheme, path, credentials or whitespace | sftp://sftp.vendor.com, sftp.vendor.com/outbound, [email protected] |
| Loopback and local names | localhost, and anything ending .local, .internal, .localhost, .localdomain |
| Private and internal IP ranges | 0.x, 127.x, 10.x, 172.16–31.x, 192.168.x, 169.254.x (the cloud metadata range), CGNAT 100.64–127.x, the IETF protocol-assignment and benchmarking ranges, multicast and reserved space |
| The IPv6 equivalents | ::1, ::, fc00::/7 unique-local, fe80::/10 link-local, and IPv4-mapped forms of any blocked address (::ffff:10.0.0.1) |
The name is also re-checked every time we actually dial — both when you read columns from the dashboard and when the poller runs. If a hostname resolves to a private address at that moment, the attempt is refused even though the connection saved cleanly. The check is deliberately strict about mixed answers: a name that resolves to both a public and a private address is refused outright rather than dialled on the public one.
How the password is stored
The password never lives in the record as text. It is encrypted with AES-256-GCM under the platform encryption key before it is written, in the same format the rest of the platform uses for stored credentials.
What follows from that:
- The dashboard never sends it back. The connections API returns only a
has_credentialsflag — which is what drives the No password set badge. There is no “show password” control anywhere, for anyone. - It is decrypted in exactly two places, both server-side: when you click Read columns from the vendor, and when the feed poller opens a session. In neither case does the plaintext leave the server or appear in a response.
- A forgotten password cannot be recovered from ILLUMA. Get a new one from the vendor and re-enter it.
- Editing without retyping is safe. Leave the password field blank and the stored one is kept; the field shows “Leave blank to keep current” as a reminder.
Test a connection: “Read columns from the vendor”
There is no separate Test connection button. The test is the Read columns from the vendor button inside the feed editor — and it’s a better test, because a connection that opens but can’t read the directory you care about is still broken.
- Open a feed on this connection — under Products or Inventory, click + Add Feed (choose the SFTP option) or Edit an existing feed. When the vendor has exactly one connection, the new feed is bound to it automatically; when it has several, the picker shows one button per endpoint so you choose deliberately.
- Fill in the Directory — under the Files heading. The button stays disabled until there’s a directory, with the hint “Enter a directory above first.”
- Optionally add a Filename Pattern and Archive Directory — the peek honours both.
- Click “Read columns from the vendor” — under Column Mapping.
- Read the result — success shows the filename and the column count, e.g.
AceCatalog_20260812.csv — 63 columns. A failure shows the reason in red.
On success, every “Vendor column…” dropdown in the feed editor — part-number column, column mappings, filter rules, category levels, location column — switches from a free-text box to a picklist of the vendor’s real headers, each showing the value from the file’s first data row. That is the point of the peek: vendors ship headers like Manufacturer#, and header names are matched exactly, so typing them from memory is how feeds silently import nothing.
📷 Screenshot: The feed editor’s Column Mapping section right after a successful peek — the “Read columns from the vendor” button, the green
filename — N columnsconfirmation beside it, and a mapping row whose left dropdown lists real vendor headers with sample values after an em dash. (placeholder — replace with/docs-images/vendors/vendor-connections-read-columns.png)
What the peek actually does
It is deliberately small and read-only:
- Lists your Directory and, if set, your Archive Directory, and picks the newest file matching the pattern across both.
- Downloads at most 64 KB of that one file — enough for a header row and a first data row.
- Parses two lines using the Delimiter you selected, and disconnects.
- Fills in Expected Columns with the real count if you left that field blank — a count taken from the actual file beats one typed from a spec sheet.
- Nothing is imported, staged, or claimed. Real ingestion only ever happens through the feed poller.
It is bounded, too: 20 seconds to complete the handshake, 45 seconds for the whole exchange. A vendor that accepts the connection and then stalls returns a timeout rather than hanging.
And it needs a password on the connection — peeking a connection with no stored credential returns “This connection has no password set yet” rather than attempting an anonymous login.
⚠️ Warning: The peek’s pattern match is case-insensitive; the poller’s is case-sensitive. A pattern of
*_catalog_*.csvcan findACME_Catalog_0812.csvin the peek and then match nothing at all on a real run. Match the vendor’s capitalisation exactly.
ℹ️ Note: If the peek cannot read a directory at all, it quietly skips it and reports “No files matching … in …” rather than a permission error. So a permission problem and an empty directory look the same here. The poller is stricter and will name it — see the troubleshooting table.
One connection, many feeds
Nothing about the connection changes when you add feeds to it. It is the same host, same login, same session behaviour. There is no cap on how many feeds ride a single connection, and no restriction on their types: an item-master product feed, a description-only enrichment product feed and two inventory feeds can all run over the same endpoint. Each keeps its own directory, filename pattern, column mapping and schedule.
ℹ️ Note: This was not always true. An older constraint allowed only one feed of each type per vendor, which forced operators into workarounds like a second vendor record for a vendor’s second file. That constraint has been removed. If you still see advice anywhere to split a vendor because “you only get one product feed”, it is out of date.
Where you see the sharing:
- On the feed editor, the Delivery field is read-only and shows the connection it runs over, e.g.
Ace B2B SFTP — SFTP sftp.vendor.com:10022 as ILLUMA1234. - In the “Add Feed” picker, when a vendor has more than one connection you get one button per endpoint, each labelled with its host, port and username, so a feed is never silently bound to the wrong one. With a single connection, the feed binds to it without asking.
- When you rotate a password, every feed on that connection picks it up. The poller re-reads the connection on each cycle rather than caching it, so a change takes effect on the next poll — no restart, no per-feed edit.
⚠️ Warning: A feed’s connection is fixed when the feed is created. The Delivery field is read-only for exactly that reason: changing which endpoint a feed runs over would repurpose a feed that already has ingest history, so it is not editable at all. To move a feed to a different endpoint, delete it and add it again from the correct connection’s + Add Feed button.
Edit or rotate a connection
- Click “Edit connection” on the connection card.
- Change what moved — label, host, port, username. Only the fields you actually change are written; editing a label cannot blank a host.
- For a new password, type it in the Password field. Leaving it blank keeps the current one.
- Click “Save Connection”.
Saving a new password also clears the connection’s stored last error — a fresh secret invalidates whatever the previous failure was.
💡 Tip: Rotating a vendor password mid-day is safe. Feeds in flight finish on the session they already opened, and the next cycle uses the new credential.
Delete a connection
Click Delete on the card and confirm. The confirmation warns that the credentials are removed and that feeds must be deleted first.
A connection with feeds still on it will not delete. The request is refused with the count and the names, e.g. “2 feeds still run over this connection (Ace nightly catalog, Ace inventory). Delete them first.” That refusal is deliberate: cascading the delete would leave those feeds pointing at nothing, and every poll would stamp them with feed's connection no longer exists. Delete the feeds first, then the connection.
A feed is named by its label, falling back to its type when it has no label — another reason to label feeds when a connection carries several. The message names at most ten of them, so on a heavily-shared connection treat the list as a sample rather than the full inventory; the Products and Inventory panels above are the complete picture.
📷 Screenshot: The refusal toast after attempting to delete a connection that still has feeds, naming the feeds and instructing you to delete them first. (placeholder — replace with
/docs-images/vendors/vendor-connections-delete-refused.png)
How the poller uses a connection
Useful context when you’re reading an error on a feed row.
| Behaviour | Detail |
|---|---|
| Authentication | Password only. If the server asks interactively instead, the same password is used to answer. There is no SSH key or certificate option. |
| Host keys | Not pinned. You do not need to exchange fingerprints with the vendor, and a vendor rotating their host key will not break your feeds. |
| Session | One session per feed per cycle: connect, list, download, disconnect. |
| Dial timeout | 30 seconds for the TCP connect, with a further 15-second grace on the SSH handshake and SFTP subsystem negotiation before the attempt is abandoned as timed out during handshake. A host that accepts TCP and then says nothing cannot hang the runner. |
| Whole-cycle limit | 20 minutes per feed, after which the session is killed and the feed is marked with an error. |
| Download style | Sequential, never parallel — required by mainframe-fronted vendor gateways, which retire a file handle if it is read in parallel. Large catalogs are therefore slower but reliable. |
| Directories | The pickup directory and, if set, the archive directory. On a scheduled run, a directory that cannot be listed is a hard error, not a skip — a permission problem must not be reported as “no new files”. |
| Credentials | Read fresh from the connection on every cycle, never cached across polls, so a rotation or a host change lands on the next run without a restart. |
| Errors | Surfaced on the feed row, not on the connection card. |
ℹ️ Note: Connections have no enable/disable switch in the dashboard — they are active from the moment you create them. To stop ILLUMA pulling from a vendor, turn the feed off. (A connection can be marked inactive at the data layer, in which case its feeds report “connection is disabled”; you will not see that from normal use.)
Troubleshooting
Peek errors appear in red beside the Read columns from the vendor button. Poller errors appear on the feed row under Products or Inventory, prefixed with Error: — hover to see the full text.
| What you see | What it means | What to do |
|---|---|---|
ssh dial host:22: ... handshake failed or an authentication failure |
Wrong username or password — or the vendor has not allowlisted us. | Re-enter the password via Edit connection. Confirm the username’s exact case with the vendor and ask whether they filter by IP. |
ssh dial host:22: timed out during handshake, or Could not read from the vendor: connect ETIMEDOUT |
Nothing is answering on that host and port. Almost always the port. | Confirm the port with the vendor. B2B endpoints often use a non-standard one (Ace: 10022). |
Reading from the vendor timed out after 45s |
The server accepted the connection but stalled while listing or transferring. | Retry. If it persists, the vendor’s directory may be enormous — narrow the Filename Pattern — or their gateway is degraded. |
list /outbound: permission denied |
The connection opened. The account cannot read that directory. | Check the path’s exact spelling and leading slash, then ask the vendor which directory your account is scoped to. |
list /outbound: file does not exist |
The directory path is wrong. | Vendors often use /outbound, /out, or a per-customer folder. Ask for the literal path. |
Peek: No files matching *_Catalog_*.csv in /outbound |
Either the directory really is empty, or the peek could not read it and skipped it silently. | Clear the pattern and peek again to prove files are visible. If it still finds nothing, treat it as a permission or path problem. |
| Peek finds the file, the feed finds nothing | Case. The peek matches patterns case-insensitively; the poller does not. | Copy the vendor’s exact capitalisation into Filename Pattern, or leave the pattern blank to take every file. |
bad filename pattern "..." |
The pattern itself is malformed — usually an unclosed [ bracket. |
Simplify it. * and ? cover nearly every vendor naming scheme; leave it blank to take every file. |
Could not resolve sftp.vendor.com |
DNS has no answer for that name. | Check for a typo. If it’s correct, the vendor may have changed hostnames. |
"10.4.2.9" is a private or internal address... |
The host points inside a private network, which ILLUMA will not dial. | Get the vendor’s public endpoint. An internal address only works from inside their network. |
Enter just the hostname — no scheme, path, or credentials |
The host field has sftp://, a path, or user@ in it. |
Put the hostname alone in Host; the directory belongs on the feed, the username in Username. |
No password set badge / This connection has no password set yet |
The connection record has no credential. | Edit connection, type the password, save. |
connection has no credentials — set them on the vendor page (on a feed) |
Same cause, seen from the poller. | As above. |
feed has no connection — assign one on the vendor page |
The feed isn’t attached to any endpoint. | Delete the feed and add it again from the correct connection’s + Add Feed button. A feed’s connection is fixed at creation and cannot be reassigned by editing the feed. |
feed's connection no longer exists |
The connection was removed out from under the feed. | Re-create the connection, then delete and re-add the feed against it — the existing feed cannot be re-pointed. |
connection is disabled |
The connection is marked inactive. | Contact support — this is not something the dashboard sets. |
2 feeds still run over this connection (...) on delete |
Deletion is blocked while feeds reference it. | Delete those feeds first, then the connection. |
AceCatalog_0812.csv appears to be empty |
The newest matching file has no usable rows after the header. | Check whether the vendor dropped a zero-byte placeholder; wait for the real drop. |
download /outbound/file.csv: transfer failed after the file opened |
Not a missing file — the transfer broke mid-stream after a successful open. | Retry on the next cycle. If it repeats on the same large file, tell the vendor their gateway is dropping long transfers. |
Stored credentials could not be read or Credential encryption is not configured on this environment |
A platform-side encryption problem, not something you can fix from the vendor page. | Contact ILLUMA support. Do not delete and re-create the connection first — the error text is the diagnostic. |
Reading files over edi isn't supported yet / transport "..." has no delivery path yet |
The connection is on a transport with no delivery path built. | Use SFTP. |
Next
With the endpoint proven — a connection that opens and a peek that returns real column headers — the next step is telling ILLUMA what’s in the file.
- Product Feeds — directories, filename patterns, column mapping, matching strategy and scheduling for the vendor’s item master, cost, MAP and identifiers.
- Inventory Feeds — the same connection, carrying stock quantities per vendor warehouse.
- Enrichment Feeds — a second product feed on the same endpoint whose only payload is long-form copy and media.
- Vendor Troubleshooting — when the endpoint is fine but the data isn’t.
