Back to Supplier Onboarding

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Supplier Onboarding Automation

[YourCompany.com] · Operations Department · Prepared by FullSpec · [Today's Date]

This document is the authoritative technical reference for the Supplier Onboarding automation build. It covers the current-state step map, all three agent specifications with IO contracts, the end-to-end data flow, and the recommended build stack. The FullSpec team uses this document to guide every build and integration decision. It assumes familiarity with REST APIs, webhook configuration, and OAuth 2.0 authentication flows.

01Process snapshot

Step
Name
Description
1
Receive Supplier Approval Notification
Operations Manager is notified via Slack or email that a new supplier has been approved and begins the onboarding sequence manually. (5 min)
2
Send Intake Form to Supplier
Ops team member emails a Google Form link to the supplier requesting business name, tax ID, bank details, and contact information. Depends on a person remembering to act. (10 min)
3
Chase Incomplete Form Responses
If the supplier does not respond within a few days, ops sends one or more follow-up emails. Commonly requires two or three chasers before the form is completed. BOTTLENECK. (20 min)
4
Collect Compliance Documents
Ops team member separately emails the supplier to request insurance certificates, NDA or trading terms, and required tax forms, often across multiple threads. (15 min)
5
Review Documents for Completeness
Ops team member manually checks each required document for presence and legibility. Missing or expired items trigger another email round. BOTTLENECK. (20 min)
6
Route for Compliance Sign-Off
Documents are forwarded to the finance lead for review. This step routinely sits in an inbox for one to three days with no structured handoff. BOTTLENECK. (15 min)
7
Send Agreement for Signature
Once compliance approves, ops prepares and sends the trading agreement via DocuSign and monitors envelope status manually. (20 min)
8
Create Supplier Record in Xero
Finance or ops team member manually keys the supplier's bank account, payment terms, and contact details into Xero after the agreement is signed. (15 min)
9
Create Supplier Contact in HubSpot
A separate HubSpot contact record is created to track the supplier relationship. This step is often missed or done inconsistently. (10 min)
10
File Documents and Notify Team
Signed agreement and compliance documents are saved to a shared folder and the team is notified via a manual Slack message. (10 min)
Time cost summary: Total manual time per supplier onboarding cycle is 140 minutes. At 8 suppliers per month, that is approximately 1,120 minutes (18.7 hours) per month and 4.2 hours per week. The automation replaces steps 2, 3, 4, 5, 6, 7, 8, 9, and 10 (all agent-handled steps), leaving only the finance lead compliance sign-off as a required human action. Target human effort post-automation is under 15 minutes per supplier.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Intake and Chaser Agent

Handles all initial supplier outreach and timed follow-up without any manual involvement. When a new approved supplier record is detected in the connected source (Google Form trigger, CRM entry, or spreadsheet row), this agent sends a personalised intake form link via Gmail and monitors for submission. If no submission is detected after 48 hours, a first reminder is dispatched automatically. A second reminder fires at 96 hours if the form remains incomplete. The agent's sole output is a confirmed, fully completed intake form submission that downstream agents can act on.

Trigger
New approved supplier record detected in the connected source (form, CRM row, or spreadsheet entry)
Tools
Gmail, Google Forms
Replaces steps
Steps 2 and 3 (Send Intake Form, Chase Incomplete Form Responses)
Estimated build
8 hours — Moderate complexity
// Input
supplier_name: string
supplier_email: string
approval_date: ISO8601 date
approved_by: string

// Output
form_submission_id: string          // Google Forms response ID
supplier_business_name: string
supplier_tax_id: string             // ABN or tax reference
supplier_bank_bsb: string
supplier_bank_account: string
supplier_primary_contact_name: string
supplier_primary_contact_email: string
supplier_primary_contact_phone: string
submission_timestamp: ISO8601 datetime
reminder_count: integer             // 0, 1, or 2
  • Gmail API requires OAuth 2.0 with scopes gmail.send and gmail.readonly. The sending Gmail account must be a verified sender in the connected Google Workspace.
  • Google Forms responses must be written to a connected Google Sheet (Forms native response sheet). The automation platform polls this sheet on a schedule of no more than 5-minute intervals or uses a webhook-compatible intermediary layer.
  • Intake form template must be finalised and locked before build begins. Any field-name change in the form after build requires a corresponding update to the field-mapping in the agent.
  • Deduplication: before sending the intake email, the agent must check whether a submission already exists for the supplier email address in the current response sheet. If a prior submission is found and it is less than 7 days old, no email is sent and the existing submission is forwarded downstream.
  • Fallback behaviour: if the Gmail send call returns a non-2xx HTTP response, the agent must log the error to the error table and post a Slack alert to the operations channel with the supplier name, email, and error code.
  • Reminder timing is anchored to the initial send timestamp stored in the workflow run context, not to a calendar cron. Both reminders must use a distinct email subject line to avoid threading with the original.
  • Confirm before build: the supplier approval trigger source must be agreed and connected (Google Sheet, HubSpot deal stage, or other). This determines the polling mechanism used in this agent.
Document Review Agent

Fires when the intake form submission is confirmed and documents are attached or linked. This agent checks submitted documents against a configured required-items checklist (insurance certificate, signed NDA or trading terms, tax form). It detects missing items and checks expiry dates on date-stamped documents where parseable. When all required items are present and valid, the agent posts a structured Slack notification to the finance lead summarising the supplier, listing each document with its status, and providing a direct approval or rejection action link. When items are missing or expired, the agent routes a gap report to the finance lead and triggers a re-request email to the supplier via Gmail. The agent does not assess the legal sufficiency of document content.

Trigger
Intake form submission confirmed with documents attached or linked (output of Intake and Chaser Agent)
Tools
Gmail, DocuSign
Replaces steps
Steps 4, 5, 6, and 7 (Collect Compliance Documents, Review for Completeness, Route for Compliance Sign-Off, Send Agreement for Signature)
Estimated build
10 hours — Moderate complexity
// Input
form_submission_id: string
supplier_name: string
supplier_email: string
supplier_tax_id: string
documents_received: array<{doc_type: string, file_url: string, expiry_date: date|null}>

// Output (all-docs-complete path)
document_review_status: 'complete' | 'incomplete'
completeness_report: array<{doc_type: string, status: 'present'|'missing'|'expired', expiry_date: date|null}>
slack_notification_ts: string       // Slack message timestamp for threading
docusign_envelope_id: string        // Created and sent on complete path
docusign_envelope_status: string    // 'sent'

// Output (gap-detected path)
document_review_status: 'incomplete'
gap_report: array<{doc_type: string, reason: 'missing'|'expired'}>
supplier_gap_email_sent: boolean
finance_alert_sent: boolean

// On approval (received from Supplier Activation Agent trigger)
docusign_envelope_signed_timestamp: ISO8601 datetime
docusign_completed_envelope_id: string
  • DocuSign integration requires an API key and a connected DocuSign account on at minimum the Standard plan (Personal plan does not support API access). Confirm the DocuSign plan tier before build.
  • The required-document checklist is stored as a configurable list in the workflow. It must be reviewed and agreed with the process owner before build. Changes to the checklist after build require a workflow update.
  • Document completeness check is a presence check and, where metadata is available, an expiry date comparison against the current date. The agent cannot read document content for legal accuracy. That responsibility stays with the finance lead.
  • DocuSign envelope template must be pre-built in the DocuSign account with the correct signer role and field placements. The agent populates the envelope template with supplier name, email, and tax ID from the intake form output. Template ID must be stored as a workflow credential variable.
  • The Slack notification to the finance lead must use a Slack Block Kit message with clearly labelled approve and flag actions tied to a Slack interactive component or a direct URL to an approval step in the automation platform.
  • Fallback: if DocuSign envelope creation fails, the agent logs the error and sends a Slack alert to the operations channel. The DocuSign send is not retried automatically; manual intervention is flagged.
  • Confirm before build: agree the Slack channel ID and the finance lead's Slack user ID for direct mentions in the notification message.
Supplier Activation Agent

Fires when the finance lead confirms compliance approval via the Slack interactive action or the connected approval step. This agent creates the supplier record in Xero (including bank account, payment terms, and tax information sourced directly from the intake form output), creates a matching contact record in HubSpot tagged as an active supplier, and posts a final Slack confirmation to the operations channel listing the supplier name, Xero contact ID, and activation date. This agent is the terminal step of the automated flow and its outputs are the source of truth for downstream procurement and accounts-payable processes.

Trigger
Finance lead confirms compliance approval in Slack or the connected approval step (output of Document Review Agent)
Tools
Xero, HubSpot, Slack
Replaces steps
Steps 8, 9, and 10 (Create Supplier Record in Xero, Create Supplier Contact in HubSpot, File Documents and Notify Team)
Estimated build
8 hours — Moderate complexity
// Input
supplier_name: string
supplier_email: string
supplier_tax_id: string
supplier_bank_bsb: string
supplier_bank_account: string
supplier_primary_contact_name: string
supplier_primary_contact_phone: string
docusign_completed_envelope_id: string
approval_confirmed_by: string       // Slack user ID of finance lead
approval_timestamp: ISO8601 datetime

// Output
xero_contact_id: string             // Created Xero contact record ID
hubspot_contact_id: string          // Created HubSpot contact record ID
slack_activation_message_ts: string // Posted to operations channel
activation_date: ISO8601 date
  • Xero API requires OAuth 2.0 with the accounting.contacts scope. The connected Xero account must have the Adviser or Standard user role to create supplier contacts. Confirm the Xero subscription plan: some lower-tier plans restrict API-created contact fields such as bank account details.
  • Before creating a Xero contact, the agent must query the Xero Contacts endpoint for an existing contact matching the supplier tax ID or email. If a match is found, the agent must not create a duplicate; instead it logs the conflict and sends a Slack alert to the operations channel for manual resolution.
  • HubSpot contact creation requires an API key or private app token with crm.objects.contacts.write scope. The contact must be tagged with the custom property supplier_status set to 'active' and the lifecycle stage set to 'other'.
  • Before creating a HubSpot contact, the agent must search by email using the HubSpot Search API to prevent duplicate records. If an existing contact is found, the agent updates the record rather than creating a new one.
  • The Slack confirmation message to the operations channel must include: supplier display name, Xero contact ID, HubSpot contact ID, activation date, and a link to the Xero contact record. Use Slack Block Kit for consistent formatting.
  • Payment terms value written to Xero must be sourced from a configurable workflow variable (e.g. NET30) and confirmed with the process owner before build. It is not derived from the intake form.
  • Confirm before build: the Xero tenant ID (for multi-org Xero accounts), the target HubSpot portal ID, and the Slack operations channel ID.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow, Supplier Onboarding Automation
// ─────────────────────────────────────────────────────────────────
// TRIGGER: New approved supplier record detected
// Source: Google Sheet row | HubSpot deal stage | spreadsheet entry
// ─────────────────────────────────────────────────────────────────
trigger.supplier_name          -> workflow.context.supplier_name
trigger.supplier_email         -> workflow.context.supplier_email
trigger.approval_date          -> workflow.context.approval_date
trigger.approved_by            -> workflow.context.approved_by

// ─────────────────────────────────────────────────────────────────
// AGENT 1: Intake and Chaser Agent
// ─────────────────────────────────────────────────────────────────

// Deduplication check
Google_Forms.response_sheet.lookup(supplier_email)
  -> IF existing_submission_age < 7_days: SKIP send, forward existing
  -> ELSE: proceed

// Initial outreach
Gmail.send({
  to:      workflow.context.supplier_email,
  subject: 'Action required: Complete your supplier onboarding form',
  body:    template_intake_email(supplier_name, form_url),
})
  -> gmail.message_id            -> workflow.context.initial_email_id
  -> send_timestamp              -> workflow.context.intake_email_sent_at

// Reminder logic (48h + 96h from intake_email_sent_at)
IF Google_Forms.response_sheet.poll() == no_submission AND elapsed >= 48h:
  Gmail.send(template_reminder_1)  -> workflow.context.reminder_1_sent_at
IF Google_Forms.response_sheet.poll() == no_submission AND elapsed >= 96h:
  Gmail.send(template_reminder_2)  -> workflow.context.reminder_2_sent_at
  workflow.context.reminder_count  = 2

// Form submission detected
Google_Forms.response_sheet.on_new_row:
  form_submission_id             -> workflow.context.form_submission_id
  supplier_business_name         -> workflow.context.supplier_business_name
  supplier_tax_id                -> workflow.context.supplier_tax_id
  supplier_bank_bsb              -> workflow.context.supplier_bank_bsb
  supplier_bank_account          -> workflow.context.supplier_bank_account
  supplier_primary_contact_name  -> workflow.context.supplier_primary_contact_name
  supplier_primary_contact_email -> workflow.context.supplier_primary_contact_email
  supplier_primary_contact_phone -> workflow.context.supplier_primary_contact_phone
  submission_timestamp           -> workflow.context.submission_timestamp

// ── HANDOFF: Intake and Chaser Agent -> Document Review Agent ────
// Payload: form_submission_id, supplier_name, supplier_email,
//          supplier_tax_id, submission_timestamp
// ─────────────────────────────────────────────────────────────────

// ─────────────────────────────────────────────────────────────────
// AGENT 2: Document Review Agent
// ─────────────────────────────────────────────────────────────────

// Document completeness check
checklist = ['insurance_certificate', 'nda_or_trading_terms', 'tax_form']
documents_received[]           -> check_each_against(checklist)
  doc.doc_type                 -> match to checklist item
  doc.expiry_date              -> compare to today() IF not null
  -> completeness_report[]     -> {doc_type, status, expiry_date}

// Branch: all docs complete and valid
IF document_review_status == 'complete':

  // Send DocuSign trading agreement
  DocuSign.Envelopes.create({
    templateId:    env.DOCUSIGN_TEMPLATE_ID,
    signerEmail:   workflow.context.supplier_email,
    signerName:    workflow.context.supplier_primary_contact_name,
    fields: {
      supplier_name:   workflow.context.supplier_business_name,
      supplier_tax_id: workflow.context.supplier_tax_id,
    }
  })
    -> docusign_envelope_id     -> workflow.context.docusign_envelope_id
    -> envelope_status          -> 'sent'

  // Notify finance lead via Slack
  Slack.chat.postMessage({
    channel: env.SLACK_FINANCE_LEAD_USER_ID,
    blocks:  template_compliance_review_block(
               supplier_name, completeness_report, docusign_envelope_id
             ),
    actions: ['approve', 'flag_gaps']
  })
    -> slack_notification_ts    -> workflow.context.slack_notification_ts

// Branch: gaps detected
IF document_review_status == 'incomplete':
  Gmail.send(template_gap_request_email(supplier_email, gap_report))
  Slack.chat.postMessage(template_gap_alert(finance_lead, gap_report))
    -> finance_alert_sent = true

// DocuSign signed event received (webhook callback)
DocuSign.Connect.webhook.on_envelope_completed:
  docusign_completed_envelope_id -> workflow.context.docusign_completed_envelope_id
  signed_timestamp               -> workflow.context.docusign_signed_at

// ── HANDOFF: Document Review Agent -> Supplier Activation Agent ──
// Trigger: Slack approval action OR DocuSign envelope completed
// Payload: supplier_name, supplier_email, supplier_tax_id,
//          supplier_bank_bsb, supplier_bank_account,
//          supplier_primary_contact_name, supplier_primary_contact_phone,
//          docusign_completed_envelope_id, approval_confirmed_by,
//          approval_timestamp
// ─────────────────────────────────────────────────────────────────

// ────────────────────────────────────────────────────────────��────
// AGENT 3: Supplier Activation Agent
// ─────────────────────────────────────────────────────────────────

// Xero deduplication
Xero.Contacts.get({ where: 'TaxNumber=="' + supplier_tax_id + '"' })
  -> IF match found: log conflict, Slack alert, HALT
  -> ELSE: proceed

// Create Xero supplier contact
Xero.Contacts.create({
  Name:            workflow.context.supplier_business_name,
  EmailAddress:    workflow.context.supplier_email,
  TaxNumber:       workflow.context.supplier_tax_id,
  BankAccountNumber: workflow.context.supplier_bank_account,
  BSBNumber:       workflow.context.supplier_bank_bsb,
  PaymentTerms:    env.DEFAULT_PAYMENT_TERMS,
  IsSupplier:      true
})
  -> xero_contact_id            -> workflow.context.xero_contact_id

// HubSpot deduplication
HubSpot.CRM.Contacts.search({ filterGroups: [{email: supplier_email}] })
  -> IF match found: update record, skip create
  -> ELSE: proceed

// Create HubSpot contact
HubSpot.CRM.Contacts.create({
  email:           workflow.context.supplier_email,
  firstname:       supplier_primary_contact_name.split(' ')[0],
  lastname:        supplier_primary_contact_name.split(' ')[1],
  phone:           workflow.context.supplier_primary_contact_phone,
  company:         workflow.context.supplier_business_name,
  supplier_status: 'active',
  lifecyclestage:  'other'
})
  -> hubspot_contact_id         -> workflow.context.hubspot_contact_id

// Post activation confirmation to Slack
Slack.chat.postMessage({
  channel: env.SLACK_OPS_CHANNEL_ID,
  blocks:  template_activation_block(
             supplier_name, xero_contact_id, hubspot_contact_id,
             activation_date, xero_record_url
           )
})
  -> slack_activation_message_ts -> workflow.context.slack_activation_message_ts

// ─────────────────────────────────────────────────────────────────
// TERMINAL: Supplier is active in Xero, HubSpot, and Slack confirmed
// ─────────────────────────────────────────────────────────────────
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation platform running one workflow per agent (three workflows total): Intake and Chaser Agent, Document Review Agent, Supplier Activation Agent. All credentials are stored in a shared, encrypted credential store within the platform. Each workflow is independently versioned and can be paused or redeployed without affecting the others.
Webhook configuration
Two inbound webhooks are required. (1) DocuSign Connect webhook: configured in the DocuSign account to POST envelope-completed events to the automation platform's public webhook URL for the Document Review Agent workflow. Endpoint must accept application/json and verify HMAC signature using env.DOCUSIGN_HMAC_SECRET. (2) Slack interactivity webhook: configured in the Slack app manifest to POST interactive action payloads (approve/flag actions) to the Supplier Activation Agent workflow trigger URL. Both endpoints must respond with HTTP 200 within 3 seconds to avoid retry loops.
Templating approach
All outbound email bodies (intake, reminder 1, reminder 2, gap request) are stored as named templates in the workflow credential/variable store. Each template uses placeholder tokens ({{supplier_name}}, {{form_url}}, {{gap_list}}) resolved at runtime. Slack Block Kit JSON structures for the compliance review message and activation confirmation are stored as template variables. DocuSign envelope template is pre-built in the DocuSign account and referenced by template ID stored as env.DOCUSIGN_TEMPLATE_ID.
Error logging
All agent-level errors (failed API calls, missing required fields, deduplication conflicts) are written to a Supabase table named automation_error_log with columns: id (uuid), workflow_name (text), error_code (text), error_message (text), payload_snapshot (jsonb), created_at (timestamptz). A database trigger on new row insertion posts a Slack alert to the operations channel via the Slack API, including the workflow name, error message, and a link to the Supabase log row. This ensures no failure is silent.
Testing approach
All agents are built and tested against sandbox or developer accounts first: DocuSign Sandbox environment, Xero Demo Company, HubSpot developer sandbox portal, and a dedicated Gmail test account. Google Forms responses are seeded manually during testing. Happy-path, missing-document, deduplication, and Slack approval flows are all validated in sandbox before credentials are switched to production. End-to-end UAT runs use three real sample supplier records with real staff acting as the finance lead approver.
Estimated total build time
Intake and Chaser Agent: 8 hours. Document Review Agent: 10 hours. Supplier Activation Agent: 8 hours. End-to-end integration testing, error logging setup, and UAT support: 2 hours. Total: 28 hours.
Credential prerequisites before build begins: Gmail OAuth 2.0 client credentials (scopes: gmail.send, gmail.readonly), Google Forms response sheet ID and service account access, DocuSign integration key and HMAC secret (Standard plan or above), Xero OAuth 2.0 credentials and tenant ID (Adviser or Standard user role), HubSpot private app token (scope: crm.objects.contacts.write), Slack app token with chat:write and reactions:write scopes, Slack channel IDs for operations and finance lead, Supabase project URL and service role key. None of the three agents can be built until their respective credentials are confirmed and connected.
For build support or questions about this specification, contact the FullSpec team at support@gofullspec.com.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Supplier Onboarding.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View