Skip to content

API reference

The SendGrail API is a small HTTP/JSON API for sending email and reading back what happened to it. This page covers the conventions every endpoint shares.

Base URL

https://api.sendgrail.com/v1

The version is part of the path. When a breaking change becomes necessary it ships as /v2 alongside /v1, so an integration keeps working until you choose to move it.

Endpoints

MethodEndpointDescription
POST/v1/emailsSend an email
POST/v1/emails/batchSend up to 100 emails
GET/v1/emailsList emails
GET/v1/emails/{id}Retrieve an email
PATCH/v1/emails/{id}Reschedule an email
POST/v1/emails/{id}/cancelCancel a scheduled email
GET/v1/emails/{id}/attachmentsList attachments

Authentication

Every request carries an API key as a bearer token:

http
Authorization: Bearer sg_xxxxxxxx
Content-Type: application/json

Keys have one of two access levels, and the difference is deliberate:

AccessCanCannot
Sendingsend, reschedule, cancelread your mail back
Fullall of the above, plus list / retrieve / attachments

A key that lives inside an application should be a Sending key. If it leaks, someone can send from your domain — bad — but they cannot download your message history, which is usually worse. Reading with a Sending key returns 403 restricted_api_key.

Every response carries a request id

http
X-Request-Id: 8f2c1e64-1b17-4f8c-9f0e-3b6c1e0f5c31

That id is the id of this call's entry in your dashboard's Logs page — which holds the exact request body, the response we sent, the status and the latency. Errors repeat it in the body:

json
{
  "message": "The to field is required.",
  "code": "validation_error",
  "errors": { "to": ["The to field is required."] },
  "request_id": "8f2c1e64-1b17-4f8c-9f0e-3b6c1e0f5c31"
}

So a misbehaving call never has to be reconstructed from a timestamp: open Logs → <request_id> and it's there, exactly as we received it. Quote the id to support and we can look at the same thing you are.

Content type

Requests are JSON. Responses are always JSON — including errors, and regardless of the Accept header you send. The API never redirects.

Idempotency

Pass an Idempotency-Key on a send and a retry with the same key returns the original result instead of sending a second copy:

http
Idempotency-Key: order-1234-receipt

Use it anywhere a retry is possible — a queue worker, a webhook handler, a mobile client on a flaky connection.

Conventions

  • Errors — one shape for every failure. See Errors.
  • Rate limits — per team, with headers on every response. See Rate limits.
  • Lists — cursor-paginated. See Pagination.
  • Ids — every object is addressed by a UUID. Internal database ids are never exposed, so an id you hold is always safe to store and to log.
  • Timestamps — ISO 8601, UTC (2026-07-14T09:41:55+00:00).
  • Unknown fields in a request body are ignored.

Transactional email on your own domain.