Certifyos Send Grid Webhook Resource API

The Send Grid Webhook Resource API from Certifyos — 2 operation(s) for send grid webhook resource.

Operations 2

POST /outreach/sendgrid/webhook/email-status Receive SendGrid delivery-status events for outreaches #
POST /outreach/sendgrid/webhook/incoming-parse Receive an inbound email reply via SendGrid Inbound Parse #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/certifyos:certifyos-send-grid-webhook-resource-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

certifyos-send-grid-webhook-resource-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  description: API for Certify application
  title: Certify API Layer Send Grid Webhook Resource API
  version: 1.0.0
servers:
- url: http://localhost:9000
  description: Local Development Server
- url: https://api-service.staging.certifyos.com
  description: Staging Server
- url: https://api-service.internal.certifyos.com
  description: Internal Server
- url: https://api-service.test.certifyos.com
  description: Test Server
- url: https://api-service.demo.certifyos.com
  description: Demo Server
- url: https://api-service.certifyos.com
  description: Production Server
tags:
- name: Send Grid Webhook Resource
paths:
  /outreach/sendgrid/webhook/email-status:
    post:
      summary: Receive SendGrid delivery-status events for outreaches
      description: 'Accepts a batch of email delivery-status events (delivered, bounced, opened, clicked, dropped, deferred, etc.) posted by SendGrid''s Event Webhook and applies each one to the matching outreach email record. Configure this URL in SendGrid''s Event Webhook settings for outreach sender identities; use the sibling POST /outreach/sendgrid/webhook/incoming-parse endpoint instead for inbound reply emails. The request body must be a non-empty JSON array of event objects; each event should carry outreach context (`tenantId`/`emailId`/`outreachId`) as top-level fields or nested under a `custom_args` object, and falls back to matching by `sg_message_id` alone when that context is absent. This call returns 200 immediately after starting processing: the delivery-status updates and the best-effort audit copy (raw payload to Cloud Storage plus a WebhookRawBlob record) all happen asynchronously in the background after the response is sent, so a 200 does not guarantee any individual event was actually applied. A body that is not a JSON array, an empty array, or an array with no event carrying a usable `sg_message_id`/`event` pair is not treated as an error - it still returns 200 and applies nothing. This is a public endpoint that does not require authentication; no tenant-id header is used.'
      operationId: handleSendGridEmailStatus
      requestBody:
        description: A JSON array of SendGrid Event Webhook objects. SendGrid batches multiple events per delivery, so a single request commonly carries events for several messages.
        content:
          application/json:
            examples:
              eventBatch:
                value:
                - email: jane.doe@example-clinic.com
                  timestamp: '1700000000'
                  event: delivered
                  category: credentialing-outreach
                  sgMessageId: 14c5d75ce93.filterdrecv.recvd-1-B.0
                - email: jane.doe@example-clinic.com
                  timestamp: '1700000032'
                  event: open
                  sgMessageId: 14c5d75ce93.filterdrecv.recvd-1-B.0
                - email: john.smith@example-clinic.com
                  timestamp: '1700000090'
                  event: bounce
                  status: 5.1.1
                  reason: 550 5.1.1 The email account does not exist
                  sgMessageId: 9b2f1a.filterdrecv.recvd-1-B.0
            schema:
              type: array
              items:
                $ref: '#/components/schemas/SendGridEvent'
        required: true
      responses:
        '200':
          description: 'Processing was started (or intentionally skipped for an empty/invalid batch). The JSON body is a bare string, not an object: "Processing N email status update events" when at least one event carried a usable sg_message_id/event pair (updates continue in the background); "No events to process" when the body was not a non-empty JSON array; or "No valid events to process" when it was an array but no event carried a usable sg_message_id/event pair. None of these are errors.'
          content:
            application/json:
              examples:
                processingStarted:
                  value: '"Processing 3 email status update events"'
              schema:
                type: string
        '401':
          description: Returned only when the event-webhook public key is configured and the request's signature/timestamp headers (X-Twilio-Email-Event-Webhook-Signature/-Timestamp, or their X-SendGrid-Webhook-* equivalents) are missing or fail verification against that key; skipped entirely when no key is configured. Resend the webhook with a valid signature from the configured SendGrid key pair.
          content:
            application/json:
              examples:
                invalidSignature:
                  value: '"Invalid or missing webhook signature"'
              schema:
                type: string
        '500':
          description: 'Returned when the body could not be parsed as JSON or an unexpected failure occurred while starting processing. The JSON body is a bare string: "Error processing webhook: <cause>". Configure SendGrid to retry this webhook on 5xx.'
          content:
            application/json:
              examples:
                processingFailed:
                  value: '"Error processing webhook: Failed to process email status webhook: Unexpected end-of-input"'
              schema:
                type: string
        '400':
          description: Bad Request
      tags:
      - Send Grid Webhook Resource
      parameters:
      - name: tenant-id
        in: header
        required: true
        description: Tenant ID
        schema:
          type: string
  /outreach/sendgrid/webhook/incoming-parse:
    post:
      summary: Receive an inbound email reply via SendGrid Inbound Parse
      description: 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.
      operationId: parseSendgridIncomingEmail
      requestBody:
        description: Multipart form data representing the parsed inbound email, as posted by SendGrid's Inbound Parse Webhook. Attachments, if any, arrive as additional parts named attachment1, attachment2, and so on.
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                to:
                  type: string
                from:
                  type: string
                subject:
                  type: string
                text:
                  type: string
                html:
                  type: string
                headers:
                  type: string
                emailId:
                  type: string
                outreachId:
                  type: string
                tenantId:
                  type: string
                workflowId:
                  type: string
        required: true
      responses:
        '200':
          description: '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.'
          content:
            text/plain:
              examples:
                processed:
                  value: 'Email processed successfully. ID: corr_7f3a9c21'
              schema:
                type: string
        '401':
          description: 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.
          content:
            text/plain:
              examples:
                missingSignature:
                  value: Missing webhook signature headers
              schema:
                type: string
        '500':
          description: '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.'
          content:
            text/plain:
              examples:
                processingFailed:
                  value: 'Error processing email: Could not find outreach for workflowId: wf_8823, tenantId: tenant_001'
              schema:
                type: string
        '400':
          description: Bad Request
      tags:
      - Send Grid Webhook Resource
      parameters:
      - name: tenant-id
        in: header
        required: true
        description: Tenant ID
        schema:
          type: string
components:
  schemas:
    Instant:
      type: string
      format: date-time
      examples:
      - '2022-03-10T16:15:50Z'
    SendGridEvent:
      type: object
      description: A single SendGrid Event Webhook object describing one delivery-status occurrence (delivered, bounce, open, click, etc.) for one recipient of one send.
      properties:
        email:
          type: string
          examples:
          - jane.doe@example-clinic.com
          description: Recipient email address the event applies to.
        timestamp:
          type: string
          examples:
          - '1700000000'
          description: Unix epoch seconds, as a string, at which SendGrid recorded the event; see getEventTime() to convert to an Instant.
        event:
          type: string
          examples:
          - delivered
          description: SendGrid event type, e.g. delivered, open, click, bounce, dropped, deferred, spamreport, unsubscribe, group_unsubscribe, group_resubscribe.
        category:
          type: string
          examples:
          - credentialing-outreach
          description: Category tag attached to the originating send, if one was set.
        sgMessageId:
          type: string
          examples:
          - 14c5d75ce93.filterdrecv.recvd-1-B.0
          description: SendGrid's message identifier for the originating send, delivered on the wire as sg_message_id; used to correlate this event back to the outreach email that generated it.
        smtp-id:
          type: string
          examples:
          - <14c5d75ce93.dfd.64b469@ismtpd-555>
          description: The smtp-id header of the originating message, if present.
        response:
          type: string
          examples:
          - 250 2.0.0 OK
          description: Raw SMTP response text from the receiving mail server; present on delivered, bounce, and deferred events.
        attempt:
          type: string
          examples:
          - '1'
          description: Delivery attempt number, as a string; present on deferred events.
        status:
          type: string
          examples:
          - 5.1.1
          description: SMTP status/response code; present on bounce and deferred events.
        reason:
          type: string
          examples:
          - 550 5.1.1 The email account does not exist
          description: Human-readable reason for the event; present on bounce, dropped, and deferred events.
        type:
          type: string
          examples:
          - bounce
          description: Bounce classification, e.g. bounce vs blocked; present on bounce events.
        eventTime:
          $ref: '#/components/schemas/Instant'
  securitySchemes:
    jwt:
      type: http
      description: JWT Authentication - Provide only the raw token without Bearer prefix
      scheme: bearer
      bearerFormat: JWT
x-provenance:
  method: harvested
  publisher: Certifyos
  source: https://api-service.internal.certifyos.com/openapi.json
  note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
    stamped by stamp-openapi-provenance.py (roadmap#793)