Ir al contenido

International Purchasing

Area: Administration Entry workflow: workflows/administration/international-purchasing.json

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.

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)

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
  • State store: Google Sheets workbook 1mucA7L-CvAkBO_mQ_2KcbJ6Lj4KCDNxjRuxvDN4ABNA (hardcoded in the Sheets nodes). Five tabs (briefs, candidates, quotes, selections, logs) — keyed by brief_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.

  • 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_typecategory (raw_material / finished_product / machinery).
Google Sheets: Append Brief n8n-nodes-base.googleSheets Persists the brief to the briefs tab.
{
"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.

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.
  • 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_price empty.
  • 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).
  • 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 in Code: Build Search Query + Code: Parse SERP To Candidates.
  • name is the listing title, not the manufacturer. Real supplier identity is enriched in Stage 2.

The discovery layer is a single linear sub-pipeline (Code: Build Search QueryHTTP Request: Search DuckDuckGoCode: Parse SERP To Candidates). To add a new source:

  1. Add a parallel sub-pipeline with its own request and parser, emitting the same candidates schema.
  2. Merge both branches before Google Sheets: Append Candidates.
  3. No change required downstream.
  • DuckDuckGo coverage for B2B/wholesale terms — may need query tuning or a fallback provider.
  • Deduplication against historical candidates rows (brief_id + name + website?). Currently appends without dedup.
  • email enrichment: visit each website in Stage 2, or rely entirely on Stage 3 outreach.

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 (candidates tab).
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 machinery branch is deferred until the external draftsman vendor and its handoff protocol are defined. The Analyst stage will be built first for finished_product and raw_material only.

  • 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.
{
"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"
}
  • 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?

Outreach and initial negotiation with shortlisted candidates via Gmail (email) and Twilio (WhatsApp).

  • Shortlist from Stage 2.
  • 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.
  • 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.
{
"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"
}
  • 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.
  • 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.
  • Negotiate final pricing where needed.
  • Pick the winning supplier(s).
  • Sign off on the procurement decision.
{
"brief_id": "...",
"selection": {
"winner_candidate_id": "uuid",
"runner_ups": ["uuid"],
"final_price": "...",
"rationale": "string",
"decided_by": "FB",
"decided_at": "<ISO-8601 timestamp>"
},
"status": "closed"
}
  • Sheet layout: one comparison tab per brief_id or a master tab with filters?
  • FX rates source for currency normalization (manual cell vs. API call)?
  • Re-negotiation loop: how many rounds before lockdown?

  • State store — Google Sheets workbook keyed by brief_id. Tabs and column schemas: google-sheets-schema.md. Each stage updates status and 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 logs tab or n8n execution metadata.
  • Human-in-the-loop checkpoints — Stages 2 (machinery drawing — deferred) and 4 (CPO decision) gate on human input.
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.

See credentials/README.md.

commercial.

  • active: false.
  • Stages 0 + 1 are the only implemented stages.
  1. Validate Stage 1 end-to-end from a non-cloud IP (DuckDuckGo may CAPTCHA Railway).
  2. Add candidate deduplication against the candidates tab before append.
  3. Define the tender message templates for Stage 2 (finished_product and raw_material branches only).
  4. Wire Stage 3 outreach using the existing Gmail and Twilio credentials; pre-approve required WhatsApp templates on Twilio.
  5. Build the Stage 4 comparison tab and the FB sign-off capture.
  6. Revisit the machinery branch once the external draftsman is selected.
  • Renamed file International Purchasing.jsoninternational-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 the Indicative MOQ form field (was relying on the n8n default).
  • Tags already include administration, purchasing, commercial — no change.
  • Stage 1 source is the DuckDuckGo HTML SERP scoped to site:alibaba.com. The Sheets tab is candidates (supplier-centric schema), not products.
  • Workbook ID is hardcoded in the three Sheets nodes (1mucA7L-CvAkBO_mQ_2KcbJ6Lj4KCDNxjRuxvDN4ABNA) instead of $env.WORKBOOK_ID.