Skip to content

feat(doordash): add DoorDash Drive integration with 13 API operations#3838

Open
waleedlatif1 wants to merge 1 commit intostagingfrom
waleedlatif1/add-doordash
Open

feat(doordash): add DoorDash Drive integration with 13 API operations#3838
waleedlatif1 wants to merge 1 commit intostagingfrom
waleedlatif1/add-doordash

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

Summary

  • Add complete DoorDash Drive integration (delivery quotes, deliveries, businesses, stores)
  • 13 operations: create/accept quote, create/get/update/cancel delivery, create/list/update business, create/list/get/update store
  • JWT-based auth (HS256) via internal API route with jose library
  • Block with conditional subBlocks, advanced mode for optional fields, wandConfig on timestamp fields

Type of Change

  • New feature

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Mar 30, 2026 1:56am

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Mar 30, 2026

PR Summary

Medium Risk
Adds a new internal API route that generates and uses JWTs to call DoorDash Drive/Developer APIs, which is security-sensitive and could impact request signing/credential handling. Remaining changes are mostly content/config updates to surface the new integration in docs and the integrations catalog.

Overview
Adds a new DoorDash Drive integration surfaced across the docs and integrations catalog, including a new DoordashIcon, block type→icon mapping updates, and a new doordash docs page with all 13 operations.

Introduces an internal Next.js API proxy at apps/sim/app/api/tools/doordash/route.ts that validates requests via zod, generates short-lived HS256 JWTs with jose, forwards requests to DoorDash drive/v2 and developer/v1 endpoints for deliveries/quotes/businesses/stores, and normalizes responses into a consistent output shape.

Written by Cursor Bugbot for commit 10bfbb6. Configure here.

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

}),
...(body.pickupTime && { pickup_time: body.pickupTime }),
...(body.dropoffTime && { dropoff_time: body.dropoffTime }),
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicated request body construction across two operations

Low Severity

The create_quote and create_delivery cases build an identical ~30-line request body object with the same fields, same conditionals, and same type conversions. A bug fix or field addition in one would need to be manually replicated in the other. Extracting a shared helper (e.g. buildDeliveryRequestBody) would eliminate this duplication.

Additional Locations (1)
Fix in Cursor Fix in Web

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 30, 2026

Greptile Summary

This PR adds a complete DoorDash Drive integration with 13 API operations (delivery quotes, deliveries, businesses, and stores). Authentication is handled via HS256 JWT generation using the jose library in a single internal API route (/api/tools/doordash), rather than OAuth. The integration follows the project's standard multi-tool block pattern and is structurally complete. Two open issues from previous review rounds remain (non-JSON error bodies, NaN from Number()). One new P1 finding: pickupTime and dropoffTime are mutually exclusive at the DoorDash API level but both fields are shown simultaneously in the UI with no guard.

Confidence Score: 4/5

Safe to merge after addressing the mutually exclusive pickupTime/dropoffTime fields, which would currently produce a DoorDash API error at runtime when both are set.

The integration is structurally complete and follows project conventions. All 13 tools are registered, credentials use correct visibility, JWT generation is sound, and the executor correctly merges partial params. A new P1 finding adds a real user-facing failure path: both pickupTime and dropoffTime are shown simultaneously in the UI with no guard, but the DoorDash API rejects requests where both are set.

apps/sim/blocks/blocks/doordash.ts (pickupTime/dropoffTime mutual exclusion, dropoffContactSendNotifications default) and apps/sim/app/api/tools/doordash/route.ts (open issues from prior review: NaN coercion, non-JSON error body).

Important Files Changed

Filename Overview
apps/sim/app/api/tools/doordash/route.ts Single POST handler for all 13 operations; JWT generation, routing, and response extraction are correct. Two issues from prior review rounds (non-JSON error bodies, NaN from Number()) remain open. New finding: base64url padding not normalised before Buffer.from().
apps/sim/blocks/blocks/doordash.ts Block config with 13 operations and conditional subBlocks is structurally sound. Two issues: pickupTime/dropoffTime shown simultaneously despite being mutually exclusive at the API level; dropoffContactSendNotifications has no 'Default' option so it always overrides the account-level default.
apps/sim/tools/doordash/types.ts Well-typed param/response interfaces covering all 13 operations; shared output property constants reduce duplication correctly.
apps/sim/tools/doordash/index.ts Barrel export renames each tool to a prefixed name (doordashXxxTool) and re-exports all types with export type; functional but the rename layer is unusual vs. direct re-exports used elsewhere.
apps/sim/tools/doordash/create_quote.ts Tool config correctly uses user-only visibility for credentials, routes to shared /api/tools/doordash endpoint, and maps response fields with null fallbacks.
apps/sim/tools/doordash/create_delivery.ts Mirrors create_quote with full delivery output fields; correct credential visibility and null fallbacks throughout.
apps/sim/tools/registry.ts All 13 DoorDash tools registered under the correct doordash_* keys; no naming conflicts observed.
apps/sim/blocks/registry.ts DoordashBlock registered in alphabetical order; no issues.

Sequence Diagram

sequenceDiagram
    participant UI as Block UI
    participant Executor as Executor (generic-handler)
    participant Tool as Tool Config
    participant Route as /api/tools/doordash
    participant DD as DoorDash API

    UI->>Executor: Block inputs (operation, creds, fields)
    Executor->>Executor: params() coerce orderValue/tip, clear empty dropdowns
    Executor->>Tool: finalInputs = {...inputs, ...transformedParams}
    Tool->>Route: POST /api/tools/doordash (operation + all params)
    Route->>Route: Zod validate body
    Route->>Route: generateJwt(developerId, keyId, signingSecret)
    Route->>DD: API call (Bearer JWT)
    DD-->>Route: JSON response
    Route->>Route: extractDeliveryOutput / extractBusinessOutput / extractStoreOutput
    Route-->>Tool: {success, output}
    Tool->>Tool: transformResponse()
    Tool-->>Executor: {success, output}
    Executor-->>UI: Block output
Loading

Reviews (2): Last reviewed commit: "feat(doordash): add DoorDash Drive integ..." | Re-trigger Greptile

Comment on lines +352 to +365
const response = await fetch(url, fetchOptions)
const data = await response.json()

if (!response.ok) {
const errorMessage =
(data as Record<string, unknown>).message ??
(data as Record<string, unknown>).error ??
`DoorDash API error (${response.status})`
logger.error('DoorDash API error', { status: response.status, error: errorMessage })
return NextResponse.json(
{ success: false, error: String(errorMessage) },
{ status: response.status }
)
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 response.json() called before response.ok check

response.json() is called unconditionally before the !response.ok guard. If DoorDash returns a non-JSON body (e.g., HTML on a 502/503 gateway error), response.json() will throw and control jumps to the outer catch, which returns a generic "Failed to communicate with DoorDash API" 500 — discarding the original HTTP status code and any meaningful error detail.

Consider reading the body as text first, then conditionally parsing as JSON:

const text = await response.text()

if (!response.ok) {
  let errorMessage: string
  try {
    const errData = JSON.parse(text) as Record<string, unknown>
    errorMessage = String(
      errData.message ?? errData.error ?? `DoorDash API error (${response.status})`
    )
  } catch {
    errorMessage = text || `DoorDash API error (${response.status})`
  }
  logger.error('DoorDash API error', { status: response.status, error: errorMessage })
  return NextResponse.json(
    { success: false, error: errorMessage },
    { status: response.status }
  )
}

const data = JSON.parse(text) as Record<string, unknown>

dropoff_address: body.dropoffAddress,
dropoff_phone_number: body.dropoffPhoneNumber,
dropoff_business_name: body.dropoffBusinessName,
order_value: Number(body.orderValue),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Number() cast without numeric validation — may produce NaN

Number(body.orderValue) is called without first validating that body.orderValue is a numeric string. If a user (or an LLM) passes a non-numeric value like "free", Number(...) returns NaN, which is serialised as null in JSON — causing a silent data issue in the DoorDash request body.

The same applies to Number(body.tip) on lines 185, 214, 234, and 269.

Consider adding a numeric refinement to the Zod schema:

orderValue: z.string().regex(/^\d+$/, 'Must be a whole number in cents').optional(),
tip: z.string().regex(/^\d+$/, 'Must be a whole number in cents').optional(),

Comment on lines +265 to +275
id: 'dropoffContactSendNotifications',
title: 'Send SMS Notifications',
type: 'dropdown',
options: [
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'true',
mode: 'advanced',
condition: { field: 'operation', value: ['create_quote', 'create_delivery'] },
},
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 dropoffContactSendNotifications defaults to 'true' — may send unexpected SMS

The dropdown defaults to value: () => 'true', meaning SMS notifications to the recipient are enabled unless the user explicitly disables them. Unlike the other boolean dropdowns (contactlessDropoff, dropoffRequiresSignature) which default to '' (off), this one opts users in by default. Because it lives under mode: 'advanced', users who never open the advanced section will unknowingly trigger SMS notifications on every delivery.

If "opt-out" is preferred, change the default:

Suggested change
id: 'dropoffContactSendNotifications',
title: 'Send SMS Notifications',
type: 'dropdown',
options: [
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'true',
mode: 'advanced',
condition: { field: 'operation', value: ['create_quote', 'create_delivery'] },
},
value: () => '',

…and add a { label: 'Default', id: '' } option so users can revert to the API default explicitly.

@waleedlatif1 waleedlatif1 deleted the branch staging April 3, 2026 23:01
@waleedlatif1 waleedlatif1 reopened this Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant