---
title: "Receive an inbound email reply via SendGrid Inbound Parse"
method: POST
path: "/outreach/sendgrid/webhook/incoming-parse"
tags: ["Send Grid Webhook Resource"]
---

# Receive an inbound email reply via SendGrid Inbound Parse

`POST /outreach/sendgrid/webhook/incoming-parse`

Accepts a multipart/form-data payload from SendGrid's Inbound Parse Webhook representing an email a practitioner or provider sent in reply to an outreach message, resolves which outreach it replies to, and creates an inbound correspondence record threading the reply to that outreach; the raw payload is also stored in Cloud Storage (best-effort, does not affect the response) for audit and replay. Configure this URL as the Inbound Parse destination for the domain that receives practitioner/provider replies; use the sibling POST /outreach/sendgrid/webhook/email-status endpoint instead for delivery-status notifications such as bounces, opens, and clicks - this endpoint does not process those. `to` must contain an address at the domain configured for inbound parsing, and `from` must contain a parseable email address; `text`, `html`, `subject`, and `headers` are all optional, and a reply with neither `text` nor `html` is stored with an empty body. The reply is first matched to its parent outreach email via the `Message-ID`/`In-Reply-To`/`References` headers; if no match is found, matching falls back to identifiers encoded in the `to` address, or to the optional `emailId`/`outreachId`/`workflowId`/`tenantId` form fields when supplied. Attachments arrive as additional multipart parts named attachment1, attachment2, and so on, and are uploaded to Cloud Storage before the correspondence record is created; a call that cannot resolve a parent outreach persists nothing beyond the best-effort raw-payload copy. This is a public endpoint that does not require authentication; no tenant-id header is used.

## Headers

- `tenant-id` string, required

## Response `200`

The reply was threaded and stored. The plain-text response body is "Email processed successfully. ID: <correspondenceId>", where <correspondenceId> is the ID of the newly created inbound correspondence record.

## Other responses

- `400` — Bad Request
- `401` — Returned only when an inbound-parse public key is configured and the request is missing the X-Twilio-Email-Event-Webhook-Signature/-Timestamp headers (or their X-SendGrid-Webhook-* equivalents); skipped entirely when no public key is configured. Resend the webhook with the required signature headers present.
- `500` — Returned for any processing failure, including an unparseable `from` address, a `to` address that does not match the configured inbound-parse domain, an unresolvable parent outreach or email thread, or a downstream storage failure; the plain-text body is "Error processing email: <cause>". Configure SendGrid to retry this webhook on 5xx so a transient downstream failure gets redelivered.

---

[API](https://skmtc.net/certifyos/apis/certify-api-layer.md) · [All operations](https://skmtc.net/certifyos/apis/certify-api-layer/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/certifyos/certify-api-layer/revisions/563848e0ecc0/schema)
