Queue one message for delivery and get its ID back.
Headers
Headers| Field | Type | Description |
|---|
Idempotency-Key | string | 1–256 characters, unique to this send. Replaying it inside 24 hours returns the original response instead of sending again. |
Body
Body| Field | Type | Description |
|---|
from* | string | The sender, as an address or Name <address>. Its domain must be one this team has verified. |
to* | string | string[] | One recipient or a list. to, cc and bcc together may not exceed 50 addresses. |
subject* | string | Up to 998 bytes of UTF-8, on one line. |
html | string | The HTML body. Send html, text or both; at least one is required. |
text | string | The plain-text body. |
›9 more fields (cc, bcc, reply_to, scheduled_at, headers, attachments, tags, template, topic_id)
Body, less common| Field | Type | Description |
|---|
cc | string | string[] | Visible copies. Counts toward the recipient cap. |
bcc | string | string[] | Blind copies. Counts toward the recipient cap. |
reply_to | string | string[] | Where replies go. Not counted toward the recipient cap. |
scheduled_at | string | ISO 8601 only, between 1 minute and 30 days from now. Natural language such as "in 1 min" is rejected. |
headers | object | Custom message headers, name to value. Headers we own — From, To, Cc, Bcc, Subject, Date, Message-ID, Return-Path, the MIME and DKIM headers, and any List-Unsubscribe* — are refused. |
attachments | object[] | Up to 100 items, each with a filename and exactly one of content (base64) or path (an https URL we fetch). Optional content_type and content_id. |
tags | object[] | Up to 50 { name, value } pairs, each matching ^[A-Za-z0-9_-]{1,256}$. Tags come back on every event for this email. |
template | object | { id, variables }. id is a template ID or alias; the template must be published, and its published version supplies html, text and, where the request omits them, subject, from and reply_to. Cannot be combined with html or text. variables maps each declared key to a string or number of at most 2000 characters; a missing key takes its fallback. |
topic_id | string | Reserved for subscription topics in a later phase. |
curl -X POST "https://api.rasket.com/emails" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042" \
-d '{
"from": "Acme <orders@send.acme.example>",
"to": ["ronald.williams@example.com"],
"subject": "Your order has shipped",
"html": "<p>Order 1042 left the warehouse this morning.</p>"
}'
const response = await fetch("https://api.rasket.com/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
"Idempotency-Key": "order-1042",
},
body: JSON.stringify({
from: "Acme <orders@send.acme.example>",
to: ["ronald.williams@example.com"],
subject: "Your order has shipped",
html: "<p>Order 1042 left the warehouse this morning.</p>"
}),
});
const { id } = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/emails",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
"Idempotency-Key": "order-1042",
},
json={
"from": "Acme <orders@send.acme.example>",
"to": ["ronald.williams@example.com"],
"subject": "Your order has shipped",
"html": "<p>Order 1042 left the warehouse this morning.</p>"
},
)
id = response.json()["id"]
Response 200
{
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
}
- A
200 means we have accepted and durably recorded the message, not that it has been delivered. Delivery is reported by events. - Bodies are capped at 2 MB of
html and text combined. - Without an
Idempotency-Key, a retried request sends a second email.
Up to 100 messages in one request, each independent.
Headers
Headers| Field | Type | Description |
|---|
Idempotency-Key | string | 1–256 characters, unique to this send. Replaying it inside 24 hours returns the original response instead of sending again. |
Body
Body| Field | Type | Description |
|---|
[]* | object[] | The body is a JSON array of 100 or fewer send objects, each shaped exactly like POST /emails. |
curl -X POST "https://api.rasket.com/emails/batch" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: nightly-digest-2026-09-09" \
-d '[
{
"from": "Acme <orders@send.acme.example>",
"to": ["ronald.williams@example.com"],
"subject": "Your order has shipped",
"html": "<p>Order 1042 left the warehouse this morning.</p>"
},
{
"from": "Acme <orders@send.acme.example>",
"to": ["ada@example.com"],
"subject": "Your order has shipped",
"html": "<p>Order 1043 left the warehouse this morning.</p>"
}
]'
const response = await fetch("https://api.rasket.com/emails/batch", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
"Idempotency-Key": "nightly-digest-2026-09-09",
},
body: JSON.stringify([
{
from: "Acme <orders@send.acme.example>",
to: ["ronald.williams@example.com"],
subject: "Your order has shipped",
html: "<p>Order 1042 left the warehouse this morning.</p>"
},
{
from: "Acme <orders@send.acme.example>",
to: ["ada@example.com"],
subject: "Your order has shipped",
html: "<p>Order 1043 left the warehouse this morning.</p>"
}
]),
});
const data = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/emails/batch",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
"Idempotency-Key": "nightly-digest-2026-09-09",
},
json=[
{
"from": "Acme <orders@send.acme.example>",
"to": ["ronald.williams@example.com"],
"subject": "Your order has shipped",
"html": "<p>Order 1042 left the warehouse this morning.</p>"
},
{
"from": "Acme <orders@send.acme.example>",
"to": ["ada@example.com"],
"subject": "Your order has shipped",
"html": "<p>Order 1043 left the warehouse this morning.</p>"
}
],
)
print(response.json())
Response 200
{
"data": [
{
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
},
{
"id": "9c1d3f28-6b04-4f77-a5e2-1c8d05b3e9a7"
}
]
}
- One
Idempotency-Key covers the whole batch, not each message in it. - IDs come back in the order they were sent.
Newest first, cursor paginated.
Query parameters
Query parameters| Field | Type | Description |
|---|
limit | integer | How many items to return, 1–100. Defaults to 20. |
after | string | Return the page that follows this item ID. Mutually exclusive with before. |
before | string | Return the page that precedes this item ID. Mutually exclusive with after. |
status | string | The last event the email reached: queued, scheduled, sent, delivery_delayed, delivered, opened, clicked, bounced, complained, failed, suppressed or canceled. |
api_key_id | string | Only emails sent with this API key. A revoked key still filters the emails it sent. |
start_date | string | ISO 8601, inclusive. Emails created before this instant are excluded. |
end_date | string | ISO 8601, inclusive. Emails created after this instant are excluded. |
search | string | Case-insensitive substring of the subject, the sender address or any recipient address. 1–200 characters. |
curl -X GET "https://api.rasket.com/emails?limit=20&search=invoice" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails?limit=20&search=invoice", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/emails?limit=20&search=invoice",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "list",
"has_more": true,
"data": [
{
"object": "email",
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
"from": "Acme <orders@send.acme.example>",
"to": ["ronald.williams@example.com"],
"cc": [],
"bcc": [],
"reply_to": [],
"subject": "Your order has shipped",
"html": "<p>Order 1042 left the warehouse this morning.</p>",
"text": null,
"message_id": "<01000199a3c4d5e6-7f8a9b0c@send.acme.example>",
"created_at": "2026-09-09T10:14:02.118Z",
"last_event": "delivered"
}
]
}
- Every filter is optional and additive. Sending none returns the same page it always did.
- Filters are applied to the query, not to the page, so
has_more describes the filtered list and paging through it never skips a row. search looks at the subject, the sender address and the recipient addresses — not the message body. % and _ match literally.
The stored message and the last event it reached.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The email's ID. |
curl -X GET "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"object": "email",
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
"from": "Acme <orders@send.acme.example>",
"to": ["ronald.williams@example.com"],
"cc": [],
"bcc": [],
"reply_to": [],
"subject": "Your order has shipped",
"html": "<p>Order 1042 left the warehouse this morning.</p>",
"text": null,
"message_id": "<01000199a3c4d5e6-7f8a9b0c@send.acme.example>",
"created_at": "2026-09-09T10:14:02.118Z",
"last_event": "delivered"
}
last_event is the furthest state this email has reached, not a history. The full timeline is on the dashboard and on your webhook.
Move a scheduled send to a new time.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The email's ID. |
Body
Body| Field | Type | Description |
|---|
scheduled_at* | string | ISO 8601 only, between 1 minute and 30 days from now. |
curl -X PATCH "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"scheduled_at": "2026-09-10T12:00:00.000Z"
}'
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
scheduled_at: "2026-09-10T12:00:00.000Z"
}),
});
const { id } = await response.json();
import os
import requests
response = requests.patch(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"scheduled_at": "2026-09-10T12:00:00.000Z"
},
)
id = response.json()["id"]
Response 200
{
"object": "email",
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
}
scheduled_at is the only field this endpoint changes.- It works only while
last_event is scheduled. Once the message has been dispatched the answer is 409 resource_locked.
Stop a send that has not gone out yet.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The email's ID. |
curl -X POST "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/cancel" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/cancel", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/cancel",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"object": "email",
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c"
}
- Cancelling an email that has already been dispatched answers
409 resource_locked; there is no recall.
What was attached to a sent email, with a signed link for each.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The email's ID. |
Query parameters
Query parameters| Field | Type | Description |
|---|
limit | integer | How many items to return, 1–100. Defaults to 20. |
after | string | Return the page that follows this item ID. Mutually exclusive with before. |
before | string | Return the page that precedes this item ID. Mutually exclusive with after. |
curl -X GET "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "list",
"has_more": false,
"data": [
{
"id": "att_5f2c9a1b7e",
"filename": "invoice-1042.pdf",
"content_type": "application/pdf",
"content_disposition": "attachment",
"size": 48213,
"download_url": "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e/download?expires=1789200000&token=1f0c…",
"expires_at": "2026-09-09T10:29:02.118Z"
}
]
}
- Cursors on this list are attachment IDs.
One attachment's metadata and a fresh signed link.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The email's ID. |
attachment_id* | string | The attachment's ID. |
curl -X GET "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"object": "attachment",
"id": "att_5f2c9a1b7e",
"filename": "invoice-1042.pdf",
"content_type": "application/pdf",
"content_disposition": "attachment",
"size": 48213,
"download_url": "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e/download?expires=1789200000&token=1f0c…",
"expires_at": "2026-09-09T10:29:02.118Z"
}
Follow the signed link and get the bytes.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The email's ID. |
attachment_id* | string | The attachment's ID. |
Query parameters
Query parameters| Field | Type | Description |
|---|
expires* | integer | Part of the signature. Copy the whole download_url; do not build this yourself. |
token* | string | The link's signature, valid for fifteen minutes and for this attachment only. |
curl -X GET "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e/download?expires=1789200000&token=1f0c9d3b8a72e5461c0d" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e/download?expires=1789200000&token=1f0c9d3b8a72e5461c0d", {
method: "GET",
headers: {
"User-Agent": "acme-billing/1.0",
},
});
console.log(response.status);
import os
import requests
response = requests.get(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/attachments/att_5f2c9a1b7e/download?expires=1789200000&token=1f0c9d3b8a72e5461c0d",
headers={
"User-Agent": "acme-billing/1.0",
},
)
print(response.status_code)
- This is the only route in the public API that takes no
Authorization header: the link carries its own signed authorization so a browser can follow it. - A
User-Agent is still required, as it is on every other route. - The response is the file itself, not JSON.
Create a link that opens a read-only view of one sent email, with no sign-in required.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The ID of the email. |
Body
Body| Field | Type | Description |
|---|
expires_in | string | How long the link stays valid, as <number><unit> with optional whitespace — 10m, 2 hours, 1 day. Units: s/sec/secs/second/seconds, m/min/mins/minute/minutes, h/hr/hrs/hour/hours, d/day/days. Defaults to 48h and cannot exceed 48 hours. |
curl -X POST "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/share" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0" \
-H "Content-Type: application/json" \
-d '{
"expires_in": "24h"
}'
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/share", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
"Content-Type": "application/json",
},
body: JSON.stringify({
expires_in: "24h"
}),
});
const { id } = await response.json();
import os
import requests
response = requests.post(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/share",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
json={
"expires_in": "24h"
},
)
id = response.json()["id"]
Response 200
{
"object": "email",
"id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
"url": "https://share.example.com/nQ8vK2xW5yB7dF1hJ4mP6rT9uA3cE0gL2iO",
"expires_at": "2026-09-11T12:00:00.000Z"
}
- Treat the URL as a secret: anyone holding it can read the message, and it is the only credential the page asks for.
- The link is returned once and is not stored — only a hash of it is kept, so it cannot be retrieved again. Create another if you lose it.
id is the ID of the email, not of the share, so it is the same value you would pass to GET /emails/{email_id}.expires_at is additive: the reference spec documents only object, id and url.- The page is served on a separate origin from the dashboard and renders the message in a sandboxed frame with remote images blocked until the reader loads them.
- An unknown, expired, or revoked link answers the same 404 page, with nothing said about which of the three it was.
Every link ever created for one email, live and withdrawn alike, newest first.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The ID of the email. |
Query parameters
Query parameters| Field | Type | Description |
|---|
limit | integer | How many items to return, 1–100. Defaults to 20. |
after | string | Return the page that follows this item ID. Mutually exclusive with before. |
before | string | Return the page that precedes this item ID. Mutually exclusive with after. |
curl -X GET "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/shares" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/shares", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/shares",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "list",
"has_more": false,
"data": [
{
"id": "0198f4c1-0000-7000-8000-000000000000",
"email_id": "4ef9a417-02e9-4d39-ad75-9611e0fcc33c",
"status": "active",
"created_at": "2026-09-09T12:00:00.000Z",
"expires_at": "2026-09-11T12:00:00.000Z",
"revoked_at": null,
"created_by_user_id": null,
"created_by_api_key_id": "a4d2f0c8-5b31-4e7a-9c62-8f0b1d4e6a75"
}
]
}
- **There is no
url here, and no endpoint can give one back.** Only a hash of each token is stored, so a link that has been lost is revoked and replaced, never re-shown. status is active while the link still opens the page, expired once expires_at has passed, and revoked once it was withdrawn. A link that was withdrawn and has also expired reads revoked.- Exactly one of
created_by_user_id and created_by_api_key_id is set, recording which credential created the link. Both are null once that member or key is gone; neither restricts who may revoke it. - Cursors are share IDs. A cursor naming a share of a different email is
422 invalid_parameter, not an empty page. - Revoked links stay in this list, and are deleted only when the email itself is.
Stop a link working, without deleting the record that it existed.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The ID of the email. |
share_id* | string | The ID of the share, as GET /emails/{email_id}/shares reports it. |
curl -X DELETE "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/shares/{share_id}" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/shares/{share_id}", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const { id } = await response.json();
import os
import requests
response = requests.delete(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/shares/{share_id}",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
id = response.json()["id"]
Response 200
{
"object": "email_share",
"id": "0198f4c1-0000-7000-8000-000000000000",
"revoked_at": "2026-09-10T09:00:00.000Z"
}
- The link stops working on the next request. There is no cache to wait for.
- Idempotent: revoking a link that is already revoked answers the instant it *first* stopped working, not the instant of this call.
- The response says
revoked_at rather than the deleted: true other deletes answer with, because the row is kept — a link that was shared and withdrawn is a fact about this email. - A share belonging to a different email, or to another team, is
404 — the same answer as one that never existed. - Any
full_access key or dashboard session may revoke any of this team's links, whichever credential created it: a customer whose key has leaked needs the dashboard to be able to shut the link off.
Everything recorded for one email — sent, delivered, bounced, opened — oldest first.
Path parameters
Path parameters| Field | Type | Description |
|---|
email_id* | string | The email's ID. |
curl -X GET "https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/events" \
-H "Authorization: Bearer $RASKET_API_KEY" \
-H "User-Agent: acme-billing/1.0"
const response = await fetch("https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/events", {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.RASKET_API_KEY}`,
"User-Agent": "acme-billing/1.0",
},
});
const data = await response.json();
import os
import requests
response = requests.get(
"https://api.rasket.com/emails/4ef9a417-02e9-4d39-ad75-9611e0fcc33c/events",
headers={
"Authorization": f"Bearer {os.environ['RASKET_API_KEY']}",
"User-Agent": "acme-billing/1.0",
},
)
print(response.json())
Response 200
{
"object": "list",
"has_more": false,
"data": [
{
"object": "email_event",
"id": "0199d2f1-4c4e-7a20-9c31-6f2b8a0e5f01",
"type": "email.delivered",
"recipient": "ronald.williams@example.com",
"occurred_at": "2026-09-09T09:20:33.412Z",
"data": {}
}
]
}
- Ordered by when each event happened, not when it arrived.
recipient is null for an event about the whole message. data is the event-specific object in the shape a webhook carries it. To ask what went wrong, see Diagnose an email on the AI reference page.