Back to GDPR / Data Privacy Request Handling

Integration and API Spec

The reference during the build: every tool connection, auth scope, field mapping, and error-handling rule.

4 pagesPDF · Technical
FS-DOC-05Technical

Integration and API Spec

GDPR / Data Privacy Request Handling

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

This document defines every integration point, authentication requirement, field mapping, and error-handling rule for the GDPR / Data Privacy Request Handling automation. It is written for the FullSpec build team and covers Typeform, HubSpot, Notion, Gmail, Slack, and the orchestration layer. All credential storage, scope strings, webhook configurations, and retry policies specified here must be implemented exactly as written. Nothing in this document requires action from [YourCompany.com] staff; all build and integration work is handled end to end by FullSpec.

01Tool inventory

Tool
Role in automation
Auth method
Min plan required
Used by agent(s)
Typeform
Structured privacy request intake form; fires the workflow trigger on submission
OAuth 2.0 / webhook secret
Basic ($29/mo)
Agent 1 (Intake and Triage)
Notion
Case record creation, audit log, draft response storage, identity verification status gate
OAuth 2.0 (internal integration token)
Plus ($16/mo)
Agent 1 and Agent 2
Gmail
Sends identity verification email and approved final response to requester
OAuth 2.0 (Google Workspace)
Free (Google Workspace account)
Agent 1 and Agent 2
HubSpot
Source of all personal data records held on the requester (CRM, deals, notes, email history)
OAuth 2.0 / private app token
Free CRM (API access included)
Agent 2 (Data Discovery)
Slack
Reviewer notification with link to Notion draft and approval prompt
OAuth 2.0 (bot token)
Free tier sufficient at current volume
Agent 2 (Data Discovery)
Workflow automation platform
Orchestration layer; hosts both agent workflows, manages credential store, handles polling and webhook receipt, retry logic, and inter-agent data passing
Platform-native credential store
Standard/Team tier (est. $49/mo)
All agents
Before you connect anything: all OAuth flows and webhook endpoints must be validated against sandbox or developer environments for every tool before production credentials are entered into the credential store. Never paste live API keys or tokens into workflow node fields directly. All secrets are stored in the platform credential store only, referenced by name.

02Per-tool integration detail

Typeform

Typeform acts as the sole authoritative intake channel. A new form submission fires an inbound webhook to the orchestration layer, which parses the payload and passes it to Agent 1. The form must be configured with required fields matching the Notion case record schema.

Auth method
OAuth 2.0 for API access; webhook payload signed with HMAC-SHA256 using the Typeform webhook secret
Required scopes
forms:read, responses:read, webhooks:write, webhooks:read
Webhook / trigger setup
Create a webhook on the target form via Typeform API POST /forms/{form_id}/webhooks. Set the destination URL to the orchestration layer's inbound webhook endpoint. Enable the secret field and store the secret value in the credential store as TYPEFORM_WEBHOOK_SECRET. The orchestration layer must validate the Typeform-Signature header (SHA256 HMAC) on every inbound request and reject any payload that fails validation with a 401 response.
Required configuration
Form ID stored in credential store as TYPEFORM_FORM_ID. Field reference IDs for request_type, requester_email, requester_name, and request_detail must be mapped in the workflow node config (not hardcoded). Field references follow the pattern ref_xxxx and are retrieved from GET /forms/{form_id}.
Rate limits
Typeform API: 200 requests/minute on Basic plan. Webhook delivery: no rate limit on inbound webhooks. At ~4 requests/month current volume, no throttling is required. A future volume threshold of 150 requests/month would warrant review.
Constraints
Typeform webhooks do not support retry on delivery failure from the Typeform side; the orchestration layer must expose a reliable public HTTPS endpoint with TLS 1.2 or higher. Form field changes that alter ref IDs require immediate update to the field mapping config.
// Inbound webhook payload (key fields)
event_id: string          // Typeform event UUID
form_response.submitted_at: ISO8601 timestamp
form_response.answers[].field.ref: string   // matches TYPEFORM_FIELD_REF_*
form_response.answers[].text: string        // requester_name, request_type, request_detail
form_response.answers[].email: string       // requester_email
// Signature header
Typeform-Signature: sha256=<hmac_hex>
Notion

Notion is used by both agents. Agent 1 creates the initial case record and writes the verification email status. Agent 2 writes the compiled draft response and updates the record when the reviewer approves. The orchestration layer polls the identity_verified field to gate Agent 2's trigger.

Auth method
Notion internal integration token (Bearer token). Token stored in credential store as NOTION_API_TOKEN.
Required scopes
Notion integrations do not use named OAuth scopes; the integration must be granted explicit access to the target database pages in the Notion UI. Required capabilities: Read content, Update content, Insert content. The integration must be connected to: Case Records database, Draft Response template database.
Webhook / trigger setup
Notion does not natively support outbound webhooks as of the current API version. Agent 2 is triggered by a polling mechanism in the orchestration layer: poll the Case Records database every 5 minutes using POST /v1/databases/{NOTION_CASES_DB_ID}/query with a filter on identity_verified = true AND agent2_triggered = false. On match, set agent2_triggered = true before dispatching to prevent duplicate runs.
Required configuration
NOTION_CASES_DB_ID: stored in credential store (the database ID of the Case Records database). NOTION_DRAFT_DB_ID: stored in credential store (the database ID for draft response pages). Property names must match exactly: Status (select), identity_verified (checkbox), agent2_triggered (checkbox), requester_email (email), requester_name (title), request_type (select: SAR, Erasure, Rectification), deadline_date (date), hubspot_contact_id (rich text), draft_page_id (relation), reviewer_name (rich text), completion_date (date), outcome (select: Approved, Rejected, Withdrawn).
Rate limits
Notion API: 3 requests/second average; bursts tolerated. At 4 requests/month with 5-minute polling intervals, approximately 8,640 poll calls/month are made. This is well within limits. No throttling is required at current volume.
Constraints
Relation properties between Case Records and Draft Response databases must be configured in Notion before the workflow is built. Checkbox properties used as gates (identity_verified, agent2_triggered) must be set to unchecked by default on page creation. The Notion API does not support transactions; write order must be enforced in the orchestration layer.
// Agent 1 creates case record (POST /v1/pages)
parent.database_id: NOTION_CASES_DB_ID
properties.requester_name.title[].text.content: string
properties.requester_email.email: string
properties.request_type.select.name: 'SAR' | 'Erasure' | 'Rectification'
properties.Status.select.name: 'Pending Verification'
properties.deadline_date.date.start: ISO8601 (submission_date + 30 days)
properties.identity_verified.checkbox: false
properties.agent2_triggered.checkbox: false
// Agent 2 updates case record (PATCH /v1/pages/{page_id})
properties.Status.select.name: 'Awaiting Review'
properties.draft_page_id.relation[].id: draft_page_id
properties.hubspot_contact_id.rich_text[].text.content: string
// Closer update after approval
properties.Status.select.name: 'Closed'
properties.completion_date.date.start: ISO8601
properties.outcome.select.name: 'Approved'
properties.reviewer_name.rich_text[].text.content: string
Gmail

Gmail is used by Agent 1 to send the identity verification email immediately after the Notion case record is created. It is used again at the end of the workflow to send the approved final response and data pack to the requester. Both sends use message templates with dynamic placeholder substitution.

Auth method
OAuth 2.0 with a dedicated Google Workspace service account or authorised user credential. Refresh token stored in credential store as GMAIL_OAUTH_REFRESH_TOKEN. Client ID and secret stored as GMAIL_CLIENT_ID and GMAIL_CLIENT_SECRET.
Required scopes
https://www.googleapis.com/auth/gmail.send, https://www.googleapis.com/auth/gmail.readonly (readonly required only if workflow reads thread for ID confirmation detection in a future enhancement; send is the minimum required scope for current build)
Webhook / trigger setup
No inbound webhook required for current build. Gmail send is an action step only. If Gmail push notifications are added in a future version to detect ID document replies, a Gmail Watch (POST /gmail/v1/users/me/watch) with a Google Cloud Pub/Sub topic would be required.
Required configuration
GMAIL_SENDER_ADDRESS: stored in credential store (the authorised sending address, e.g. privacy@[yourdomain]). Two email template IDs stored in the credential store: GMAIL_VERIFICATION_TEMPLATE_ID and GMAIL_RESPONSE_TEMPLATE_ID. Templates must contain placeholders: {{requester_name}}, {{request_type}}, {{deadline_date}}, {{case_id}}, {{notion_case_url}}. Templates are stored in Notion or the orchestration platform's template store, not hardcoded in workflow nodes.
Rate limits
Gmail API: 250 quota units/second per user; sending limit 500 messages/day on standard Workspace accounts. At 4 requests/month generating 2 emails each (8 emails/month), no throttling is required. No rate-limit handling needed at current volume.
Constraints
The sending address must have OAuth consent granted and must not be a generic shared inbox that another process already has an exclusive OAuth grant on. SPF and DKIM records must be valid on the sending domain to avoid deliverability issues. All emails sent to requesters must include the business's full legal name and postal address per GDPR Article 12 requirements.
// Gmail send (POST /gmail/v1/users/me/messages/send)
// Verification email (Agent 1)
to: requester_email (from Typeform payload)
subject: 'Your privacy request has been received - identity verification required'
body: render(GMAIL_VERIFICATION_TEMPLATE_ID, {
  requester_name, request_type, deadline_date, case_id, notion_case_url
})
// Final response email (Agent 2, post-approval)
to: requester_email (from Notion case record)
subject: 'Your {{request_type}} request - response from [YourCompany.com]'
body: render(GMAIL_RESPONSE_TEMPLATE_ID, {
  requester_name, request_type, completion_date, reviewer_name, data_summary_url
})
attachments: [data_pack.pdf] if request_type == 'SAR'
Integration and API SpecPage 1 of 3
FS-DOC-05Technical
HubSpot

HubSpot is the primary source of personal data held on the requester. Agent 2 queries HubSpot via the CRM API once identity is confirmed in Notion, retrieving contact records, associated deals, notes, and email history. All retrieved data is structured and written to the Notion draft response page.

Auth method
HubSpot Private App token (preferred over OAuth for server-to-server automation). Token stored in credential store as HUBSPOT_PRIVATE_APP_TOKEN. Included in all API requests as Authorization: Bearer {HUBSPOT_PRIVATE_APP_TOKEN}.
Required scopes
crm.objects.contacts.read, crm.objects.deals.read, crm.objects.notes.read, crm.objects.emails.read, crm.schemas.contacts.read, crm.schemas.deals.read, timeline.read
Webhook / trigger setup
HubSpot is queried as an action step only; no inbound HubSpot webhook is required. Agent 2 initiates the query after the Notion poll detects identity_verified = true.
Required configuration
HUBSPOT_PORTAL_ID: stored in credential store. Contact lookup uses the requester_email field from the Notion case record as the primary identifier (GET /crm/v3/objects/contacts/search with filterGroups on email property). If no match is found, the case record Status must be updated to 'Manual Review Required' and a Slack alert sent. Associated object type IDs for deals, notes, and emails must not be hardcoded; retrieve via GET /crm/v3/schemas and cache the IDs in the credential store as HUBSPOT_DEAL_TYPE_ID, HUBSPOT_NOTE_TYPE_ID, HUBSPOT_EMAIL_TYPE_ID.
Rate limits
HubSpot Free CRM API: 100 requests/10 seconds and 40,000 requests/day. Each Agent 2 run makes approximately 5 to 8 API calls (contact search, associations, deal fetch, notes fetch, email fetch, property schema). At 4 requests/month this produces roughly 32 API calls/month. No throttling is required. Implement a 500ms inter-call delay as a precaution.
Constraints
HubSpot private app tokens do not expire but must be rotated if exposed. The token must have access scoped to the minimum required objects listed above. For erasure requests, this workflow retrieves data only; deletion must be performed manually or via a separate deletion workflow with explicit confirmation. The API returns a maximum of 100 associated objects per call; pagination must be implemented for contacts with large deal or note histories.
// Contact search (POST /crm/v3/objects/contacts/search)
filterGroups[0].filters[0].propertyName: 'email'
filterGroups[0].filters[0].operator: 'EQ'
filterGroups[0].filters[0].value: requester_email
properties: ['firstname','lastname','email','phone','createdate','hs_lead_status']
// Association fetch (GET /crm/v4/objects/contacts/{contact_id}/associations/{object_type})
// Returns: deal IDs, note IDs, email IDs
// Deal detail (GET /crm/v3/objects/deals/{deal_id})
properties: ['dealname','amount','dealstage','createdate','closedate']
// Notes (GET /crm/v3/objects/notes/{note_id})
properties: ['hs_note_body','hs_timestamp','hubspot_owner_id']
// Output written to Notion draft page
contact_summary: { id, name, email, phone, created, lead_status }
deals: [{ id, name, amount, stage, created, closed }]
notes: [{ id, body, timestamp, owner_id }]
email_count: integer
Slack

Slack delivers the reviewer notification at the end of Agent 2's run, providing a direct link to the Notion draft and an explicit approval prompt. The message is sent to a designated private channel or direct message to the assigned reviewer. No inbound Slack interaction is used in the current build; approval is recorded in Notion directly.

Auth method
Slack Bot Token (OAuth 2.0 app installation). Token stored in credential store as SLACK_BOT_TOKEN. Bot must be installed to the workspace and invited to the target channel.
Required scopes
chat:write, chat:write.public (if the target channel is public), channels:read, users:read (to resolve reviewer Slack user ID from email if using DM delivery)
Webhook / trigger setup
No inbound Slack webhook is required. Outbound message is sent via POST https://slack.com/api/chat.postMessage. The target channel ID is stored in the credential store as SLACK_REVIEWER_CHANNEL_ID. If direct message to reviewer is preferred, the reviewer's Slack user ID must be stored as SLACK_REVIEWER_USER_ID. Do not hardcode channel names; use IDs only.
Required configuration
SLACK_BOT_TOKEN: credential store. SLACK_REVIEWER_CHANNEL_ID: credential store. Message block template must include: case ID, requester name, request type, deadline date, direct URL to Notion draft page, and explicit instruction text ('Please review the draft in Notion and mark the case as Approved or Rejected before responding here.'). Message blocks are defined in the workflow node config as Slack Block Kit JSON, not as plain text.
Rate limits
Slack API Tier 3: 50 requests/minute for chat.postMessage. At 4 messages/month, no throttling is required. Slack enforces a 1 message/second burst soft limit per channel; the orchestration layer must not fire more than 1 message per second to the same channel.
Constraints
Slack message delivery is not guaranteed if the bot is not in the channel or the channel is archived. The orchestration layer must check the API response ok field and treat ok: false as a retryable error. Slack Workflow Builder is not used; all messages are sent via API calls from the orchestration layer only.
// Outbound message (POST https://slack.com/api/chat.postMessage)
channel: SLACK_REVIEWER_CHANNEL_ID
blocks: [
  { type: 'header', text: 'Privacy Request Ready for Review' },
  { type: 'section', fields: [
    { type: 'mrkdwn', text: '*Case ID:* {{case_id}}' },
    { type: 'mrkdwn', text: '*Requester:* {{requester_name}}' },
    { type: 'mrkdwn', text: '*Type:* {{request_type}}' },
    { type: 'mrkdwn', text: '*Deadline:* {{deadline_date}}' }
  ]},
  { type: 'section', text: { type: 'mrkdwn',
    text: '<{{notion_draft_url}}|Open draft in Notion>' }},
  { type: 'section', text: { type: 'mrkdwn',
    text: 'Mark the case Approved or Rejected in Notion before responding.' }}
]
// Expected API response
{ ok: true, channel: string, ts: string }

03Field mappings between tools

The tables below define the exact field mappings for each agent handoff. All source and destination field names are written in their native API format. The orchestration layer is responsible for all transformation logic between formats.

Agent 1 handoff: Typeform submission to Notion case record creation

Source tool
Source field
Destination tool
Destination field
Typeform
form_response.answers[ref=TYPEFORM_FIELD_REF_NAME].text
Notion
properties.requester_name.title[0].text.content
Typeform
form_response.answers[ref=TYPEFORM_FIELD_REF_EMAIL].email
Notion
properties.requester_email.email
Typeform
form_response.answers[ref=TYPEFORM_FIELD_REF_TYPE].choice.label
Notion
properties.request_type.select.name
Typeform
form_response.answers[ref=TYPEFORM_FIELD_REF_DETAIL].text
Notion
properties.request_detail.rich_text[0].text.content
Typeform
form_response.submitted_at (ISO8601)
Notion
properties.submission_date.date.start
Orchestration layer (computed)
submitted_at + 30 days (ISO8601)
Notion
properties.deadline_date.date.start
Typeform
event_id
Notion
properties.typeform_event_id.rich_text[0].text.content
Orchestration layer (generated)
uuid()
Notion
properties.case_id.rich_text[0].text.content

Agent 1 handoff: Notion case record to Gmail verification email

Source tool
Source field
Destination tool
Destination field
Notion
properties.requester_email.email
Gmail
to (recipient address)
Notion
properties.requester_name.title[0].text.content
Gmail
template placeholder {{requester_name}}
Notion
properties.request_type.select.name
Gmail
template placeholder {{request_type}}
Notion
properties.deadline_date.date.start
Gmail
template placeholder {{deadline_date}}
Notion
properties.case_id.rich_text[0].text.content
Gmail
template placeholder {{case_id}}
Notion
page.url (computed from page id)
Gmail
template placeholder {{notion_case_url}}

Agent 2 handoff: Notion case record to HubSpot query

Source tool
Source field
Destination tool
Destination field
Notion
properties.requester_email.email
HubSpot
filterGroups[0].filters[0].value (contact search email filter)
HubSpot
contacts.results[0].id
Notion
properties.hubspot_contact_id.rich_text[0].text.content

Agent 2 handoff: HubSpot retrieved data to Notion draft response page

Source tool
Source field
Destination tool
Destination field
HubSpot
contacts.results[0].properties.firstname + lastname
Notion (draft page)
properties.contact_full_name.title[0].text.content
HubSpot
contacts.results[0].properties.email
Notion (draft page)
properties.contact_email.email
HubSpot
contacts.results[0].properties.phone
Notion (draft page)
properties.contact_phone.phone_number
HubSpot
contacts.results[0].properties.createdate
Notion (draft page)
properties.crm_created_date.date.start
HubSpot
contacts.results[0].properties.hs_lead_status
Notion (draft page)
properties.lead_status.select.name
HubSpot
deals[] (serialised JSON)
Notion (draft page)
children[].paragraph.rich_text[].text.content (Deals section)
HubSpot
notes[] (serialised JSON)
Notion (draft page)
children[].paragraph.rich_text[].text.content (Notes section)
HubSpot
email_count (integer)
Notion (draft page)
properties.email_record_count.number

Agent 2 handoff: Notion draft page to Slack reviewer notification

Source tool
Source field
Destination tool
Destination field
Notion
properties.case_id.rich_text[0].text.content
Slack
blocks[1].fields[0].text (Case ID field)
Notion
properties.requester_name.title[0].text.content
Slack
blocks[1].fields[1].text (Requester field)
Notion
properties.request_type.select.name
Slack
blocks[1].fields[2].text (Type field)
Notion
properties.deadline_date.date.start
Slack
blocks[1].fields[3].text (Deadline field)
Notion
draft_page.url (computed)
Slack
blocks[2].text.text (Notion draft hyperlink)

Final handoff: Notion approved case record to Gmail final response email

Source tool
Source field
Destination tool
Destination field
Notion
properties.requester_email.email
Gmail
to (recipient address)
Notion
properties.requester_name.title[0].text.content
Gmail
template placeholder {{requester_name}}
Notion
properties.request_type.select.name
Gmail
template placeholder {{request_type}}
Notion
properties.reviewer_name.rich_text[0].text.content
Gmail
template placeholder {{reviewer_name}}
Notion (draft page)
draft_page.url
Gmail
template placeholder {{data_summary_url}}
Orchestration layer (computed)
now() ISO8601
Notion
properties.completion_date.date.start
Integration and API SpecPage 2 of 3
FS-DOC-05Technical

04Build stack and orchestration

Orchestration layout
Two discrete workflows in the automation platform: one per agent. Agent 1 workflow (Intake and Triage) is webhook-triggered. Agent 2 workflow (Data Discovery) is poll-triggered. Both workflows share a single credential store instance. No direct inter-workflow API calls; handoff is mediated via Notion field state (identity_verified and agent2_triggered flags).
Agent 1 trigger mechanism
Inbound webhook. The orchestration platform exposes a unique HTTPS endpoint. Typeform posts the form submission payload to this endpoint on each new submission. HMAC-SHA256 signature validation is applied at the entry node using TYPEFORM_WEBHOOK_SECRET before any further processing. Invalid signatures return HTTP 401 and write an alert to the platform error log.
Agent 2 trigger mechanism
Polling (5-minute interval). The orchestration platform runs a scheduled query against the Notion Case Records database every 5 minutes. Filter: identity_verified = true AND agent2_triggered = false. On match, the workflow immediately sets agent2_triggered = true on the Notion record (optimistic lock) and proceeds. If the Notion PATCH fails, the workflow aborts and retries on the next poll cycle. This prevents duplicate Agent 2 executions for the same case.
Credential store contents
See code block below. All values are environment-scoped (production / sandbox). No credential value appears in any workflow node configuration field directly.
Webhook signature validation
Typeform: compare X-Typeform-Signature header value against HMAC-SHA256(TYPEFORM_WEBHOOK_SECRET, raw_request_body). Reject on mismatch. Slack: no inbound webhook in current build; not applicable.
Data residency
All data in transit between tools uses TLS 1.2 or higher. No personal data is written to orchestration platform logs. Log entries must use case_id as the identifier only, not requester_name or requester_email.
Credential store: all keys required in both sandbox and production environments
// ---- Typeform ----
TYPEFORM_WEBHOOK_SECRET        = '<hmac_secret_from_typeform_webhook_settings>'
TYPEFORM_FORM_ID               = '<form_id_from_typeform_dashboard>'
TYPEFORM_FIELD_REF_NAME        = '<ref_string_for_requester_name_field>'
TYPEFORM_FIELD_REF_EMAIL       = '<ref_string_for_requester_email_field>'
TYPEFORM_FIELD_REF_TYPE        = '<ref_string_for_request_type_field>'
TYPEFORM_FIELD_REF_DETAIL      = '<ref_string_for_request_detail_field>'

// ---- Notion ----
NOTION_API_TOKEN               = '<internal_integration_token>'
NOTION_CASES_DB_ID             = '<database_id_for_case_records>'
NOTION_DRAFT_DB_ID             = '<database_id_for_draft_response_pages>'

// ---- Gmail ----
GMAIL_CLIENT_ID                = '<google_oauth_client_id>'
GMAIL_CLIENT_SECRET            = '<google_oauth_client_secret>'
GMAIL_OAUTH_REFRESH_TOKEN      = '<authorised_user_refresh_token>'
GMAIL_SENDER_ADDRESS           = 'privacy@[yourdomain]'
GMAIL_VERIFICATION_TEMPLATE_ID = '<template_identifier_in_template_store>'
GMAIL_RESPONSE_TEMPLATE_ID     = '<template_identifier_in_template_store>'

// ---- HubSpot ----
HUBSPOT_PRIVATE_APP_TOKEN      = '<private_app_token_from_hubspot_settings>'
HUBSPOT_PORTAL_ID              = '<hubspot_portal_id>'
HUBSPOT_DEAL_TYPE_ID           = '<object_type_id_for_deals>'
HUBSPOT_NOTE_TYPE_ID           = '<object_type_id_for_notes>'
HUBSPOT_EMAIL_TYPE_ID          = '<object_type_id_for_email_engagements>'

// ---- Slack ----
SLACK_BOT_TOKEN                = '<bot_oauth_token_xoxb-...>'
SLACK_REVIEWER_CHANNEL_ID      = '<channel_id_not_channel_name>'
SLACK_REVIEWER_USER_ID         = '<slack_user_id_for_dm_fallback>'

// ---- Orchestration ----
ENV                            = 'sandbox' | 'production'
POLL_INTERVAL_SECONDS          = '300'
All credential store keys must be duplicated in a sandbox environment before the production environment is populated. Sandbox values must point to sandbox/test instances of each tool only. Never share credential values between environments. Rotate all tokens immediately if an environment variable is accidentally logged or exposed.

05Error handling and retry logic

Every integration point has a defined failure behaviour. Unhandled exceptions must never fail silently. All retryable errors use exponential backoff starting at 30 seconds, doubling on each attempt, with a maximum of 3 retry attempts before the failure is escalated. All non-retryable errors trigger an immediate alert to the FullSpec monitoring channel and write a structured error entry to the platform error log with case_id, integration name, error code, and timestamp.

Integration
Scenario
Required behaviour
Typeform webhook inbound
HMAC signature validation fails
Reject with HTTP 401. Write error log entry. Do not process payload. Alert monitoring channel. No retry (invalid signature is not a transient error).
Typeform webhook inbound
Webhook delivery timeout or orchestration endpoint unavailable
Typeform will not retry; orchestration layer must maintain 99.9% uptime. On recovery, FullSpec must manually retrieve missed submissions via GET /forms/{form_id}/responses filtered by submitted_at range and reprocess.
Notion: case record creation (Agent 1)
Notion API returns 4xx or 5xx on page creation
Retry up to 3 times with exponential backoff (30s, 60s, 120s). On third failure, write error log and send alert to SLACK_REVIEWER_CHANNEL_ID with error detail. Do not proceed to Gmail verification send. Mark case as 'Creation Failed' in error log.
Notion: polling for identity_verified (Agent 2 trigger)
Notion API unavailable during poll cycle
Skip poll cycle. Log transient failure. Resume on next scheduled poll (5 minutes). No alert unless 3 consecutive poll cycles fail, at which point send a monitoring alert.
Notion: agent2_triggered lock write fails
PATCH to set agent2_triggered = true returns an error after identity confirmed
Abort Agent 2 execution. Do not proceed to HubSpot query. Retry on next poll cycle. This prevents duplicate HubSpot queries and duplicate Slack notifications for the same case.
Gmail: verification email send (Agent 1)
Gmail API returns 4xx (auth failure or quota exceeded)
Retry once after 60 seconds. If second attempt fails, write error to log and update Notion case record Status to 'Verification Email Failed'. Send Slack alert to reviewer channel with case_id and error detail. Manual send required.
Gmail: final response email send (post-approval)
Gmail API returns 5xx or timeout
Retry up to 3 times with exponential backoff (30s, 60s, 120s). If all retries fail, update Notion case Status to 'Response Send Failed' and alert reviewer via Slack. Manual send required within SLA window. Log all retry attempts with timestamps.
HubSpot: contact search returns no results
Requester email not found in HubSpot CRM
Not a retryable error. Update Notion case Status to 'Manual Review Required'. Send Slack alert: 'No HubSpot record found for {{requester_email}} on case {{case_id}}. Manual data retrieval required.' Do not proceed to draft response compilation.
HubSpot: API returns 429 (rate limit exceeded)
Burst of requests exceeds 100/10s limit
Pause execution. Wait for the duration specified in the Retry-After response header (or 10 seconds if absent). Retry the failed request once. If second attempt also rate-limited, abort the run, log the failure, and alert monitoring. At current volume (4 requests/month) this scenario is not expected.
HubSpot: association pagination
Contact has more than 100 associated objects of a single type
The orchestration layer must follow the paging.next.link cursor in the HubSpot response to fetch all pages before proceeding. Failure to paginate results in an incomplete data disclosure, which is a GDPR compliance risk. Log the total object count retrieved per run.
Slack: reviewer notification send fails
Slack API returns ok: false (bot not in channel, invalid token, or channel archived)
Retry once after 30 seconds. If second attempt fails, attempt DM delivery to SLACK_REVIEWER_USER_ID. If DM also fails, write error log and send email notification to the reviewer address via Gmail as a fallback. Do not leave the reviewer unnotified.
Any integration: unhandled exception
Unexpected error type not covered by the above scenarios
Catch-all error handler in each workflow must: stop execution, write a structured error log entry (case_id, workflow name, node name, error type, error message, timestamp, stack trace if available), and send an immediate alert to the FullSpec monitoring channel. Never fail silently. The case Notion record Status must be set to 'Error - Manual Intervention Required'.
For any error state that updates a Notion case record Status, the orchestration layer must confirm the Notion PATCH succeeded. If the error-state write itself fails, a secondary alert must be sent to support@gofullspec.com with the full error context so the record can be updated manually.
Integration and API SpecPage 3 of 3

More documents for this process

Every document generated for GDPR / Data Privacy Request Handling.

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