International Purchasing
Area: Administration Entry workflow: workflows/administration/international-purchasing.json
Purpose
Sección titulada «Purpose»End-to-end international supplier sourcing pipeline. A procurement brief enters via a public form and is processed by a chain of agents — data entry, analysis, contact / negotiation — closing with a human review handled by FB (CPO) for final pricing comparison.
The goal is to run the discovery and shortlisting like a tender: structured brief in, comparable apples-to-apples quotes out.
Pipeline overview
Sección titulada «Pipeline overview»Form Trigger | v[Stage 0] Brief Intake (this workflow) | v[Stage 1] Agent: Data Entry ──> Candidates DB | v[Stage 2] Agent: Analyst ──> Filtered shortlist (per category) | v[Stage 3] Agent: Contactor ──> Outreach + quotes (Gmail / WhatsApp) | v[Stage 4] Human: CPO Negotiation ──> Final supplier selection (FB)Implementation status
Sección titulada «Implementation status»All four stages live in a single n8n workflow (workflows/administration/international-purchasing.json). Stage boundaries are organizational, not workflow boundaries.
| Stage | Component | Status |
|---|---|---|
| 0 | Brief Intake | Implemented |
| 1 | Agent: Data Entry | Implemented (prototype, single source: DuckDuckGo SERP → Alibaba) |
| 2 | Agent: Analyst | Planned |
| 3 | Agent: Contactor | Planned |
| 4 | Human: CPO Negotiation | Planned |
Locked-in decisions
Sección titulada «Locked-in decisions»- State store: Google Sheets workbook
1mucA7L-CvAkBO_mQ_2KcbJ6Lj4KCDNxjRuxvDN4ABNA(hardcoded in the Sheets nodes). Five tabs (briefs,candidates,quotes,selections,logs) — keyed bybrief_id. Schema: google-sheets-schema.md. - Orchestration: one monolithic workflow, not sub-workflows.
- Stage 1 discovery: DuckDuckGo HTML SERP scoped to
site:alibaba.com. Prototype with a single source first, but keep the discovery layer pluggable so new sources can be added without rewriting downstream stages. - Stage 2 draftsman: external vendor (TBD). Build of the machinery branch is deferred until that piece is defined.
- Stage 3 channels: Gmail (existing credentials) for email; Twilio for WhatsApp (existing credentials).
- Stage 4 surface: Google Sheets — normalized quotes rendered side-by-side for FB.
Stage 0 — Brief Intake (current)
Sección titulada «Stage 0 — Brief Intake (current)»Trigger
Sección titulada «Trigger»- Type: Form Trigger (public form).
- Fields: supply type, technical specification, certifications, priority countries, amount range, MOQ, incoterm, max lead time, target supplier count, free-form notes.
| Node | Type | Purpose |
|---|---|---|
Form Trigger: Receive Brief |
n8n-nodes-base.formTrigger |
Public form entry point. |
Code: Normalize Brief |
n8n-nodes-base.code |
Maps form fields to canonical brief schema; categorizes supply_type → category (raw_material / finished_product / machinery). |
Google Sheets: Append Brief |
n8n-nodes-base.googleSheets |
Persists the brief to the briefs tab. |
Output schema (Code: Normalize Brief)
Sección titulada «Output schema (Code: Normalize Brief)»{ "brief_id": "<ISO-8601 timestamp>", "supply_type": "Raw Material | Finished Product | Industrial Machinery", "category": "raw_material | finished_product | machinery", "specification": "string", "certifications": ["OEKO-TEX", "..."], "priority_countries": ["India", "..."], "amount_range": "string", "moq": "string | null", "incoterm": "Any | FOB | CIF | EXW | DDP | FCA", "max_lead_time": "No restriction | 30 days | ...", "target_count": 30, "notes": "string", "status": "pending", "executed_at": "<ISO-8601 timestamp>"}active: false— activate per-environment.
Stage 1 — Agent: Data Entry
Sección titulada «Stage 1 — Agent: Data Entry»Builds a candidate database from the normalized brief. Prototype: scrapes the DuckDuckGo HTML SERP (scoped to site:alibaba.com) and maps results to the candidates schema.
- Normalized brief from Stage 0 (especially
category,specification,priority_countries,target_count).
| Node | Type | Purpose |
|---|---|---|
OpenAI: Extract Search Keywords |
@n8n/n8n-nodes-langchain.openAi |
Message a Model (gpt-4o-mini, JSON output) — derives 2-5 product keywords from spec. |
Code: Build Search Query |
n8n-nodes-base.code |
Builds a DuckDuckGo query site:alibaba.com <keywords> <country> suppliers. |
HTTP Request: Search DuckDuckGo |
n8n-nodes-base.httpRequest |
GET https://html.duckduckgo.com/html/?q=... with a desktop User-Agent. Response as text. |
Code: Parse SERP To Candidates |
n8n-nodes-base.code |
Regex-parses the HTML SERP, decodes DDG redirects, keeps only alibaba.com links, emits one item per candidate. |
Google Sheets: Append Candidates |
n8n-nodes-base.googleSheets |
Persists candidate rows to the candidates tab. |
Google Sheets: Update Brief Status |
n8n-nodes-base.googleSheets |
Sets briefs.status = data_entry_done for the current brief_id. executeOnce: true so we update one brief row even when many candidates fan out. |
Discovery details
Sección titulada «Discovery details»- Source: DuckDuckGo HTML SERP (
html.duckduckgo.com/html/). Free and unauthenticated, but rate-limited and occasionally returns an anti-bot interstitial — see Known limitations below. - Fields populated:
candidate_id(UUID),brief_id,name,country,website(Alibaba supplier URL),source = "alibaba",confidence_score(heuristic by SERP position),analyst_notes(snippet text),discovered_at,last_updated_at. Defaults:qualification_status = "pending",artifact_drawing_status = "n/a",artifact_sample_status = "n/a",certifications = "[]",email/whatsapp/moq/lead_time/indicative_priceempty. - Fields left empty:
email,whatsapp,moq,lead_time,indicative_price— none of these are extractable from a SERP snippet. Filled by Stage 2 (analyst enrichment) and Stage 3 (direct outreach).
Known limitations
Sección titulada «Known limitations»- DuckDuckGo anti-bot. On some egress IPs (notably Railway / cloud datacenters) the HTML endpoint returns a CAPTCHA interstitial instead of the SERP. If that happens, swap the HTTP node for a real SERP provider (e.g. Serper.dev, SerpAPI, ScraperAPI) — the rest of the pipeline only depends on the parsed candidate JSON shape so the swap is contained.
- Alibaba-only. The query is hard-scoped to
site:alibaba.com. Adding Made-in-China, Global Sources, IndiaMART etc. means adding new branches inCode: Build Search Query+Code: Parse SERP To Candidates. nameis the listing title, not the manufacturer. Real supplier identity is enriched in Stage 2.
Scalability
Sección titulada «Scalability»The discovery layer is a single linear sub-pipeline (Code: Build Search Query → HTTP Request: Search DuckDuckGo → Code: Parse SERP To Candidates). To add a new source:
- Add a parallel sub-pipeline with its own request and parser, emitting the same
candidatesschema. - Merge both branches before
Google Sheets: Append Candidates. - No change required downstream.
Open questions
Sección titulada «Open questions»- DuckDuckGo coverage for B2B/wholesale terms — may need query tuning or a fallback provider.
- Deduplication against historical
candidatesrows (brief_id+name+website?). Currently appends without dedup. emailenrichment: visit eachwebsitein Stage 2, or rely entirely on Stage 3 outreach.
Stage 2 — Agent: Analyst (planned)
Sección titulada «Stage 2 — Agent: Analyst (planned)»Applies a deeper, category-aware filter to shortlist verified suppliers. Operates like a tender: each branch has predetermined process messages.
- Candidate list from Stage 1 (
candidatestab).
Routing (by category)
Sección titulada «Routing (by category)»| Category | Required artifact | Owner |
|---|---|---|
machinery |
Technical drawing approved by FB | External draftsman (tbd), FB |
finished_product |
Sample coordination (request + receive) | Analyst agent |
raw_material |
Sample shipment / digital specs | Analyst agent |
The
machinerybranch is deferred until the external draftsman vendor and its handoff protocol are defined. The Analyst stage will be built first forfinished_productandraw_materialonly.
Responsibilities
Sección titulada «Responsibilities»- Send the tender brief to each candidate’s seller using a predetermined message template.
- Track responses, missing data, and disqualifications.
- For machinery: gate on FB’s drawing approval before proceeding.
- For finished products / raw materials: coordinate sample logistics.
Output (proposed)
Sección titulada «Output (proposed)»{ "brief_id": "...", "shortlist": [ { "candidate_id": "uuid", "qualification_status": "qualified | pending | rejected", "artifact_status": { "drawing": "approved | pending", "sample": "received | requested | n/a" }, "analyst_notes": "string" } ], "status": "analyst_done"}Open questions
Sección titulada «Open questions»- External draftsman vendor selection and handoff protocol (machinery branch — deferred).
- For raw materials: physical samples vs. digital specs? Cost / time threshold?
- SLA per category before auto-disqualification?
Stage 3 — Agent: Contactor (planned)
Sección titulada «Stage 3 — Agent: Contactor (planned)»Outreach and initial negotiation with shortlisted candidates via Gmail (email) and Twilio (WhatsApp).
- Shortlist from Stage 2.
Responsibilities
Sección titulada «Responsibilities»- Send templated outreach (RFQ) over Gmail and WhatsApp.
- Track threads, parse responses, and request missing data (price, lead time, payment terms).
- Persist conversation logs and structured quote data in Google Sheets.
- Escalate stalled threads.
Tooling
Sección titulada «Tooling»- Gmail node (
n8n-nodes-base.gmail) — credentials already configured. - Twilio node (
n8n-nodes-base.twilio) — credentials already configured; WhatsApp sender via Twilio Business API. - Inbound side: Gmail trigger + Twilio webhook for incoming WhatsApp messages.
Output (proposed)
Sección titulada «Output (proposed)»{ "brief_id": "...", "quotes": [ { "candidate_id": "uuid", "channel": "gmail | whatsapp", "quote": { "price": "...", "currency": "USD", "incoterm": "FOB", "lead_time": "60 days", "payment_terms": "..." }, "thread_id": "...", "last_message_at": "<ISO-8601 timestamp>", "status": "open | quoted | stalled | closed" } ], "status": "contactor_done"}Open questions
Sección titulada «Open questions»- Sender identity: shared inbox vs. per-user Gmail?
- Twilio WhatsApp template approval (Meta requires pre-approved templates for outbound).
- Compliance / audit log requirements?
Stage 4 — Human: CPO Negotiation (planned)
Sección titulada «Stage 4 — Human: CPO Negotiation (planned)»Final pricing review by FB (CPO). The pipeline normalizes all quotes to comparable terms so the decision is apples-to-apples.
- Quotes from Stage 3.
Responsibilities (system)
Sección titulada «Responsibilities (system)»- Normalize quotes to a common incoterm and currency for fair comparison.
- Render side-by-side comparison in a Google Sheets tab (one row per supplier, columns = normalized quote fields).
- Capture FB’s final selection and rationale.
Responsibilities (FB)
Sección titulada «Responsibilities (FB)»- Negotiate final pricing where needed.
- Pick the winning supplier(s).
- Sign off on the procurement decision.
Output (proposed)
Sección titulada «Output (proposed)»{ "brief_id": "...", "selection": { "winner_candidate_id": "uuid", "runner_ups": ["uuid"], "final_price": "...", "rationale": "string", "decided_by": "FB", "decided_at": "<ISO-8601 timestamp>" }, "status": "closed"}Open questions
Sección titulada «Open questions»- Sheet layout: one comparison tab per
brief_idor a master tab with filters? - FX rates source for currency normalization (manual cell vs. API call)?
- Re-negotiation loop: how many rounds before lockdown?
Cross-cutting concerns
Sección titulada «Cross-cutting concerns»- State store — Google Sheets workbook keyed by
brief_id. Tabs and column schemas: google-sheets-schema.md. Each stage updatesstatusand appends rows. - Idempotency — Each stage should be re-runnable without duplicating rows (use
brief_id+ candidate dedup key). - Observability — Log every external call (scraper hit, email send, Twilio send) into a
logstab or n8n execution metadata. - Human-in-the-loop checkpoints — Stages 2 (machinery drawing — deferred) and 4 (CPO decision) gate on human input.
Credentials
Sección titulada «Credentials»| Credential type | Used by |
|---|---|
googleSheetsOAuth2Api |
Google Sheets: Append Brief, Google Sheets: Append Candidates, Google Sheets: Update Brief Status (same credential Google Sheets account). |
openAiApi |
OpenAI: Extract Search Keywords (OpenAI account). |
| (none) | HTTP Request: Search DuckDuckGo — unauthenticated. |
commercial.
active: false.- Stages 0 + 1 are the only implemented stages.
Next steps
Sección titulada «Next steps»- Validate Stage 1 end-to-end from a non-cloud IP (DuckDuckGo may CAPTCHA Railway).
- Add candidate deduplication against the
candidatestab before append. - Define the tender message templates for Stage 2 (
finished_productandraw_materialbranches only). - Wire Stage 3 outreach using the existing Gmail and Twilio credentials; pre-approve required WhatsApp templates on Twilio.
- Build the Stage 4 comparison tab and the FB sign-off capture.
- Revisit the machinery branch once the external draftsman is selected.
Changelog
Sección titulada «Changelog»Standardization pass
Sección titulada «Standardization pass»- Renamed file
International Purchasing.json→international-purchasing.json(kebab-case; area folder identifies the domain). - Reordered
nodes[]array to follow execution order (Form → Normalize → Append Brief → OpenAI → Build Query → DuckDuckGo → Parse SERP → Append Candidates → Update Brief Status). - Added five sticky notes:
Stage 0: Brief Intake,Stage 1: Agent Data Entry, plus deferred stickies for Stages 2 / 3 / 4. - Added explicit
fieldType: "text"to theIndicative MOQform field (was relying on the n8n default). - Tags already include
administration,purchasing,commercial— no change.
Discovery source — DuckDuckGo (current)
Sección titulada «Discovery source — DuckDuckGo (current)»- Stage 1 source is the DuckDuckGo HTML SERP scoped to
site:alibaba.com. The Sheets tab iscandidates(supplier-centric schema), notproducts. - Workbook ID is hardcoded in the three Sheets nodes (
1mucA7L-CvAkBO_mQ_2KcbJ6Lj4KCDNxjRuxvDN4ABNA) instead of$env.WORKBOOK_ID.