All posts

SOP: connect contact forms with Orbitype, Vercel and SendGrid

A practical guide to send reliable contact notifications from Nuxt forms on Vercel with SendGrid, with optional contact storage in Orbitype.

Technical flow connecting a contact form, a server route, email delivery and a database

To connect a Nuxt contact form with SendGrid and Orbitype safely, keep one principle in place: the browser sends data only to your server; the server validates it, sends the notification, and optionally stores it. That keeps secrets out of the client and prevents an optional database failure from hiding a valid lead.

This SOP is for Nuxt 3 sites using Orbitype headless and deployed on Vercel. The intended result is a POST /api/contacts route that notifies SENDGRID_TO_EMAIL and can insert a submission into a contacts table.

Visitor
  → site form
  → Nuxt/Vercel POST /api/contacts
  → SendGrid Mail Send → lead inbox
  → Orbitype SQL (optional) → contacts table

The server route is the only place that knows SENDGRID_API_KEY and the Orbitype SQL key. Set the submitter’s email as Reply-To; do not use it as the sender because SendGrid requires the sender to be verified.

What you need before starting

  • A form that sends JSON to POST /api/contacts.
  • A SendGrid account with a Mail Send API key.
  • A SendGrid-verified sender address or domain.
  • Local and Vercel environment variables.
  • Orbitype SQL access only if submissions need to be stored.

If your form already connects to an email audience, apply the same server-side integration principle described in this secure form-to-email procedure: private keys must never be included in JavaScript downloaded by visitors.

1. Configure SendGrid correctly

Create an API key in Settings → API Keys with the minimum Mail Send permission. Then verify the address—or preferably the domain—you will use as SENDGRID_FROM_EMAIL in Settings → Sender Authentication.

The route needs these variables:

VariablePurpose
SENDGRID_API_KEYAuthenticates Mail Send requests.
SENDGRID_FROM_EMAILA SendGrid-verified sender address.
SENDGRID_FROM_NAMEDisplay name for the notification.
SENDGRID_TO_EMAILInbox that receives new leads.

A 403 response or an unverified-sender message nearly always means SENDGRID_FROM_EMAIL has no valid identity. While the client’s domain is being verified, temporarily use an address already approved in the same SendGrid account.

2. Make Orbitype optional contact storage

Email delivery is the critical outcome: it prevents a lead from being missed. Orbitype adds a searchable copy of the submission, but its unavailability should not turn a valid form submission into an error for the visitor.

The SQL integration uses these variables:

ORBITYPE_MOCK=false
ORBITYPE_API_SQL_URL="https://core.orbitype.com/api/sql/v1"
ORBITYPE_API_SQL_KEY="your-orbitype-sql-key"

If needed, create a table that reflects the form’s actual payload:

CREATE TABLE IF NOT EXISTS contacts (
  id varchar(255) DEFAULT uid() PRIMARY KEY,
  first_name text DEFAULT ''::text,
  last_name text DEFAULT ''::text,
  email text DEFAULT ''::text,
  phone text DEFAULT ''::text,
  interest text DEFAULT ''::text,
  learner_type text DEFAULT ''::text,
  message text DEFAULT ''::text,
  created_at timestamptz DEFAULT CURRENT_TIMESTAMP
);

Keep form field names, API validation, and database columns aligned. If interest becomes a different field, update all three places in the same change.

3. Use the same environment contract locally and in production

Use real values in your local .env only; that file must not be committed. Keep the names and safe placeholders in .env.example:

# SendGrid
SENDGRID_API_KEY="SG...."
SENDGRID_FROM_EMAIL="verified-sender@example.com"
SENDGRID_FROM_NAME="Site name"
SENDGRID_TO_EMAIL="leads@example.com"

# Orbitype: optional when contacts are stored
ORBITYPE_MOCK=false
ORBITYPE_API_SQL_URL="https://core.orbitype.com/api/sql/v1"
ORBITYPE_API_SQL_KEY="your-sql-api-key"

In Vercel, add the same set under Settings → Environment Variables for Production and, if forms are reviewed before release, Preview too. Then create a new deployment: adding a variable does not update an existing deployment.

4. Required behavior for POST /api/contacts

The route should validate required fields before contacting external services. Once validation succeeds, send the email and store the contact when Orbitype is enabled. If email delivery fails, return a clear error rather than pretending the lead was received. If email succeeds but storage fails, keep the success response and record the storage state safely.

A useful response distinguishes the outcomes:

{
  "ok": true,
  "emailed": true,
  "stored": false
}

Never return keys, full provider payloads, or internal implementation details to the browser. In server logs, avoid retaining messages or personal data longer than necessary.

5. Test the complete flow

Restart Nuxt after editing environment values. Then send a controlled request to your local route:

curl -s -X POST http://127.0.0.1:3000/api/contacts \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Test",
    "last_name": "User",
    "email": "you@example.com",
    "phone": "+41 00 000 00 00",
    "interest": "example",
    "learner_type": "example",
    "message": "Connectivity test"
  }'

Confirm these points in order:

  1. The API returns ok: true and emailed: true.
  2. The configured inbox receives the message and staff can reply directly to the submitter.
  3. When Orbitype is enabled, the expected row exists in contacts.
  4. After deploying on Vercel, repeat the test through the public form.

Common issues and fixes

SymptomLikely causeRecommended action
SendGrid returns 403Sender is not verifiedVerify the domain or use an approved FROM address.
400 for missing fieldsPayload does not match the routeCheck field names, types, and form validation.
emailed: true, stored: falseMissing table or SQL keyCreate contacts and configure Orbitype variables.
Works locally but not on VercelMissing values or old deploymentConfigure Production/Preview and redeploy.
Email does not arriveWrong inbox, spam, or delayCheck Spam, SENDGRID_TO_EMAIL, and SendGrid activity.

Go-live checklist

  • SendGrid Mail Send API key created.
  • SENDGRID_FROM_EMAIL verified.
  • SENDGRID_* available locally and in Vercel.
  • Orbitype SQL table and key configured when needed.
  • Field validation and Reply-To implemented in the route.
  • Local test confirms email delivery and, when applicable, storage.
  • Production was redeployed after secrets were configured.
  • No .env file or API key was added to Git.

The implementation is reliable when the visitor receives an honest outcome, the team receives the lead, and optional services never silence a valid contact request. Keeping that priority order protects both the operation and its credentials.

// stuck on something similar?

Let's debug it together

Book a call More posts