Giant Context
Giant ContextGet Early Access

Email

Manage email campaigns, templates, recipients, and tracking.


POST

Send transactional email

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/actions/send

Sends a single transactional email to a specific recipient using an email template. Used for one-off emails like order confirmations, password resets, etc.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
BodyRequired
toRequired
string
locale
stringRecipient locale (e.g., 'en', 'fr'). Resolves TranslatableString fields and passes through to block rendering. Defaults to 'en'.
emailSlugRequired
stringEmail template slug
variables
objectTemplate variables to replace
skipTracking
booleanSkip adding tracking pixel/links
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });const { apps } = await gc.projects.listProjectApps({  organizationId: org.id,  projectId: projects[0].id,});
const result = await gc.email.sendTransactionalEmail({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id,  data: {    to: "user@example.com",    subject: "Hello",    body: "World"  }});
GET

Get one contact's sent and planned emails with per-send opens and clicks

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/contacts/{contactId}/timeline

Returns the unified email timeline for a contact: past sends + planned sends (including staged sends from a Mind sends draft when present), each with per-send engagement stats (opens, clicks, bounced, complained). Each send carries its `draftId` (non-null only while staged in a ready draft). The response-level `draftId` points at the contact's active sends draft when one exists — use it to render accept/reject UI. Order is COALESCE(sent_at, scheduled_for, created_at) DESC so upcoming planned sends appear at the top, then recent sent, then older.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
contactIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const timeline = await gc.email.getContactEmailTimeline({  organizationId: org.id,  projectId: projects[0].id,  appId: "your-app-id",  contactId: "your-contact-id",});
GET

Get one email with its full content blocks and header/footer links

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}

Returns a single email by ID, including name, subject line, trigger description, full content blocks, header/footer references, and timestamps.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
emailIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "default" });
const { projects } = await gc.projects.listProjects({  organizationId: org.id});
const { apps } = await gc.projects.listProjectApps({  organizationId: org.id,  projectId: projects[0].id});
const { emails } = await gc.emails.listEmails({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id});
const email = await gc.emails.getEmail({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id,  emailId: emails[0].id});
DELETE

Delete email

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}

Soft-deletes an email by moving it to the project trash. Can be restored from trash later.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
emailIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const result = await gc.email.deleteEmail({  organizationId: org.id,  projectId: projects[0].id,  appId: "app_123",  emailId: "email_123"});
PATCH

Update an email's name, slug, subject and send-trigger sentence, not content or status

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}

Updates the fields that describe an email rather than govern it: its internal name and slug, the subject line, and the trigger description saying when the Mind should send it. Only the fields you send are changed. An email is sent rather than served, so its slug is an internal reference and changing it breaks no link. Subject is the reader-facing string; emails have no title. Can rebind the header and footer. Cannot change the email's content or status — use the block tools for content.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
emailIdRequired
path · string
BodyRequired
name
stringInternal use only
slug
stringInternal reference for this email. Emails are sent rather than served, so this is not a public URL and changing it breaks no link.
subject
union
footerId
unionThe footer this email renders with. Discover ids with listEmailFooters. Null unbinds and falls back to the app default.
headerId
unionThe header this email renders with. Discover ids with listEmailHeaders. Null unbinds and falls back to the app default.
triggerDescription
union
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const result = await gc.email.updateEmailMeta({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-123",  emailId: "email-456",  data: { subject: "Updated Subject" }});
GET

Get email recipient

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipients/{recipientId}

Returns a single recipient row with subscription state.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
emailIdRequired
path · string
recipientIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "default-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const recipient = await gc.email.getEmailRecipient({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-id",  emailId: "email-id",  recipientId: "recipient-id",});
POST

Unsubscribe a contact from one email; the row is kept for resubscribe

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipients/{recipientId}/unsubscribe

Soft-unsubscribes a recipient by setting unsubscribed_at and an optional reason. The row is preserved for audit + resubscribe.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
emailIdRequired
path · string
recipientIdRequired
path · string
BodyRequired
reason
string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "default" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const result = await gc.email.unsubscribeEmailRecipient({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-123",  emailId: "email-123",  recipientId: "rec-123",  data: {}});
GET

List one email's subscribers, including past unsubscribes, newest subscription first

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipients

Returns the subscribers for a specific email template. Includes currently subscribed and previously unsubscribed contacts.

Parameters
page
query · numberPage number to return, 1-indexed. Defaults to 1.
pageSize
query · numberItems per page (1-100). Defaults to 10.
lite
query · stringWhen 'true', return only essential fields (id, slug, title/name) to reduce payload size. Useful for context fetching and link resolution.
sort
query · stringSort specifier as 'field:direction'. Sortable fields: subscribedAt, unsubscribedAt, createdAt, updatedAt. Direction is 'asc' or 'desc' and defaults to 'asc'.
contactId
query · stringFilter by contactId. Operators: contactId=value (equals), contactId_ne, contactId_gt, contactId_gte, contactId_lt, contactId_lte, contactId_like (contains), contactId_isnull=true|false, contactId_has=value (jsonb array contains), contactId[]=a&contactId[]=b (in).
subscribedAt
query · stringFilter by subscribedAt. Operators: subscribedAt=value (equals), subscribedAt_ne, subscribedAt_gt, subscribedAt_gte, subscribedAt_lt, subscribedAt_lte, subscribedAt_like (contains), subscribedAt_isnull=true|false, subscribedAt_has=value (jsonb array contains), subscribedAt[]=a&subscribedAt[]=b (in).
unsubscribedAt
query · stringFilter by unsubscribedAt. Operators: unsubscribedAt=value (equals), unsubscribedAt_ne, unsubscribedAt_gt, unsubscribedAt_gte, unsubscribedAt_lt, unsubscribedAt_lte, unsubscribedAt_like (contains), unsubscribedAt_isnull=true|false, unsubscribedAt_has=value (jsonb array contains), unsubscribedAt[]=a&unsubscribedAt[]=b (in).
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
emailIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "default-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const { recipients } = await gc.email.listEmailRecipients({  organizationId: org.id,  projectId: projects[0].id,  appId: "target-app-id",  emailId: "target-email-id",});
POST

Subscribe a CRM contact to one email; resubscribes if previously unsubscribed

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipients

Adds a contact as a recipient of this email. If the contact was previously unsubscribed, the row is resurrected (unsubscribed_at cleared).

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
emailIdRequired
path · string
BodyRequired
contactIdRequired
string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";\n\nconst gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });\n\nconst { id: organizationId } = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });\nconst { projects } = await gc.projects.listProjects({ organizationId });\n\nconst result = await gc.email.subscribeEmailRecipient({\n  organizationId,\n  projectId: projects[0].id,\n  appId: "app-123",\n  emailId: "email-123",\n  data: { email: "user@example.com" }\n});\n
GET

List emails in an email app, newest first; pass lite=true to skip content

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails

Returns a list of all emails for the specified app. Each email includes its name, subject line, trigger description, content blocks, and associated header/footer references.

Parameters
page
query · numberPage number to return, 1-indexed. Defaults to 1.
pageSize
query · numberItems per page (1-100). Defaults to 10.
lite
query · stringWhen 'true', return only essential fields (id, slug, title/name) to reduce payload size. Useful for context fetching and link resolution.
sort
query · stringSort specifier as 'field:direction'. Sortable fields: name, slug, status, createdAt, updatedAt. Direction is 'asc' or 'desc' and defaults to 'asc'.
search
query · stringFree-text search. Matched against: name, subject.
status
query · stringFilter by status. Operators: status=value (equals), status_ne, status_gt, status_gte, status_lt, status_lte, status_like (contains), status_isnull=true|false, status_has=value (jsonb array contains), status[]=a&status[]=b (in).
slug
query · stringFilter by slug. Operators: slug=value (equals), slug_ne, slug_gt, slug_gte, slug_lt, slug_lte, slug_like (contains), slug_isnull=true|false, slug_has=value (jsonb array contains), slug[]=a&slug[]=b (in).
name
query · stringFilter by name. Operators: name=value (equals), name_ne, name_gt, name_gte, name_lt, name_lte, name_like (contains), name_isnull=true|false, name_has=value (jsonb array contains), name[]=a&name[]=b (in).
headerId
query · stringFilter by headerId. Operators: headerId=value (equals), headerId_ne, headerId_gt, headerId_gte, headerId_lt, headerId_lte, headerId_like (contains), headerId_isnull=true|false, headerId_has=value (jsonb array contains), headerId[]=a&headerId[]=b (in).
footerId
query · stringFilter by footerId. Operators: footerId=value (equals), footerId_ne, footerId_gt, footerId_gte, footerId_lt, footerId_lte, footerId_like (contains), footerId_isnull=true|false, footerId_has=value (jsonb array contains), footerId[]=a&footerId[]=b (in).
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });const { apps } = await gc.projects.listProjectApps({  organizationId: org.id,  projectId: projects[0].id,});
const { emails } = await gc.email.listEmails({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id,});
GET

Get one footer's block content in full; listEmailFooters lite=true returns metadata only

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/footers/{footerId}

Returns a single email footer by ID, including its name, content blocks, and timestamps.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
footerIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const footer = await gc.email.getEmailFooter({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-id",  footerId: "footer-id",});
DELETE

Delete email footer

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/footers/{footerId}

Permanently deletes an email footer.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
footerIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const result = await gc.email.deleteEmailFooter({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-id",  footerId: "footer-id",});
GET

List footers in an email app, newest first; pass lite=true to skip content

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/footers

Returns a list of all email footers for the specified app. Footers contain branding, unsubscribe links, and legal text appended to emails.

Parameters
page
query · numberPage number to return, 1-indexed. Defaults to 1.
pageSize
query · numberItems per page (1-100). Defaults to 10.
lite
query · stringWhen 'true', return only essential fields (id, slug, title/name) to reduce payload size. Useful for context fetching and link resolution.
sort
query · stringSort specifier as 'field:direction'. Sortable fields: name, createdAt, updatedAt. Direction is 'asc' or 'desc' and defaults to 'asc'.
search
query · stringFree-text search. Matched against: name.
name
query · stringFilter by name. Operators: name=value (equals), name_ne, name_gt, name_gte, name_lt, name_lte, name_like (contains), name_isnull=true|false, name_has=value (jsonb array contains), name[]=a&name[]=b (in).
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });const { apps } = await gc.projects.listProjectApps({  organizationId: org.id,  projectId: projects[0].id,});
const { footers } = await gc.email.listEmailFooters({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id,});
POST

Create a footer shell; only name is required, add blocks afterwards

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/footers

Creates a new email footer with content blocks for branding, unsubscribe links, and legal text.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
BodyRequired
nameRequired
string
content
array
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const { id: orgId } = await gc.organizations.getOrganizationBySlug({ slug: "default" });const { projects } = await gc.projects.listProjects({ organizationId: orgId });const { apps } = await gc.projects.listProjectApps({  organizationId: orgId,  projectId: projects[0].id});
const footer = await gc.email.createEmailFooter({  organizationId: orgId,  projectId: projects[0].id,  appId: apps[0].id,  data: { content: "Unsubscribe" }});
GET

Get one header's full block tree; no lite mode, so expect heavy output

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/headers/{headerId}

Returns a single email header by ID, including its name, content blocks, and timestamps.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
headerIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const header = await gc.email.getEmailHeader({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-id",  headerId: "header-id",});
DELETE

Delete email header

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/headers/{headerId}

Permanently deletes an email header.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
headerIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const appId = "your-app-id";const headerId = "your-header-id";
const result = await gc.email.deleteEmailHeader({  organizationId: org.id,  projectId: projects[0].id,  appId,  headerId,});
GET

List headers in an email app, newest first; pass lite=true to skip content

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/headers

Returns a list of all email headers for the specified app. Headers contain branding and navigation elements prepended to emails.

Parameters
page
query · numberPage number to return, 1-indexed. Defaults to 1.
pageSize
query · numberItems per page (1-100). Defaults to 10.
lite
query · stringWhen 'true', return only essential fields (id, slug, title/name) to reduce payload size. Useful for context fetching and link resolution.
sort
query · stringSort specifier as 'field:direction'. Sortable fields: name, createdAt, updatedAt. Direction is 'asc' or 'desc' and defaults to 'asc'.
search
query · stringFree-text search. Matched against: name.
name
query · stringFilter by name. Operators: name=value (equals), name_ne, name_gt, name_gte, name_lt, name_lte, name_like (contains), name_isnull=true|false, name_has=value (jsonb array contains), name[]=a&name[]=b (in).
createdAt
query · stringFilter by createdAt. Operators: createdAt=value (equals), createdAt_ne, createdAt_gt, createdAt_gte, createdAt_lt, createdAt_lte, createdAt_like (contains), createdAt_isnull=true|false, createdAt_has=value (jsonb array contains), createdAt[]=a&createdAt[]=b (in).
updatedAt
query · stringFilter by updatedAt. Operators: updatedAt=value (equals), updatedAt_ne, updatedAt_gt, updatedAt_gte, updatedAt_lt, updatedAt_lte, updatedAt_like (contains), updatedAt_isnull=true|false, updatedAt_has=value (jsonb array contains), updatedAt[]=a&updatedAt[]=b (in).
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });const { apps } = await gc.projects.listProjectApps({  organizationId: org.id,  projectId: projects[0].id,});
const { headers } = await gc.email.listEmailHeaders({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id,});
POST

Create a header shell; only name is required, add blocks afterwards

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/headers

Creates a new email header with content blocks for branding and navigation.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
BodyRequired
nameRequired
string
content
array
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const result = await gc.email.createEmailHeader({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-123",  data: {}});
GET

Get one send with its full delivery and engagement event log

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/sends/{sendId}

Returns a single send row and its full event log (delivered/open/click/bounce/complaint/unsubscribe).

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
sendIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const emailSend = await gc.email.getEmailSend({  organizationId: org.id,  projectId: projects[0].id,  appId: "your-app-id",  sendId: "your-send-id",});
PATCH

Update a send to reschedule or cancel; only planned and queued rows accept edits

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/sends/{sendId}

Reschedule, cancel, or adjust metadata on a send row. Cannot modify rows with status='sent' or status='failed'.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
sendIdRequired
path · string
BodyRequired
status
union
metadata
object
scheduledFor
union
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });
const result = await gc.email.updateEmailSend({  organizationId: org.id,  projectId: projects[0].id,  appId: "app-123",  sendId: "send-456",  data: {},});
GET

List past, queued and planned sends across the app, filterable by email or contact

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/sends

Returns the log of sends (past + planned + queued) for this email app. Filter by email, contact, or status. Sorted by effective time (sent_at, then scheduled_for, then created_at) descending.

Parameters
page
query · numberPage number to return, 1-indexed. Defaults to 1.
pageSize
query · numberItems per page (1-100). Defaults to 10.
lite
query · stringWhen 'true', return only essential fields (id, slug, title/name) to reduce payload size. Useful for context fetching and link resolution.
sort
query · stringSort specifier as 'field:direction'. Sortable fields: status, scheduledFor, sentAt, createdAt, updatedAt. Direction is 'asc' or 'desc' and defaults to 'asc'.
search
query · stringFree-text search. Matched against: recipientEmail.
emailId
query · stringFilter by emailId. Operators: emailId=value (equals), emailId_ne, emailId_gt, emailId_gte, emailId_lt, emailId_lte, emailId_like (contains), emailId_isnull=true|false, emailId_has=value (jsonb array contains), emailId[]=a&emailId[]=b (in).
contactId
query · stringFilter by contactId. Operators: contactId=value (equals), contactId_ne, contactId_gt, contactId_gte, contactId_lt, contactId_lte, contactId_like (contains), contactId_isnull=true|false, contactId_has=value (jsonb array contains), contactId[]=a&contactId[]=b (in).
status
query · stringFilter by status. Operators: status=value (equals), status_ne, status_gt, status_gte, status_lt, status_lte, status_like (contains), status_isnull=true|false, status_has=value (jsonb array contains), status[]=a&status[]=b (in).
locale
query · stringFilter by locale. Operators: locale=value (equals), locale_ne, locale_gt, locale_gte, locale_lt, locale_lte, locale_like (contains), locale_isnull=true|false, locale_has=value (jsonb array contains), locale[]=a&locale[]=b (in).
recipientEmail
query · stringFilter by recipientEmail. Operators: recipientEmail=value (equals), recipientEmail_ne, recipientEmail_gt, recipientEmail_gte, recipientEmail_lt, recipientEmail_lte, recipientEmail_like (contains), recipientEmail_isnull=true|false, recipientEmail_has=value (jsonb array contains), recipientEmail[]=a&recipientEmail[]=b (in).
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });const { apps } = await gc.projects.listProjectApps({  organizationId: org.id,  projectId: projects[0].id,});
const { emailSends } = await gc.email.listEmailSends({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id,});
POST

Create a send for one contact; defaults to planned, which sends nothing until queued

/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/sends

Creates a send row. Mind writes status='planned' rows that it reorders as new CRM activity lands. When Mind commits to firing, it transitions to status='queued' with scheduled_for set; a worker picks it up.

Parameters
organizationIdRequired
path · string
projectIdRequired
path · string
appIdRequired
path · string
BodyRequired
locale
string
status
union
emailIdRequired
string
metadata
object
contactIdRequired
string
scheduledFor
string
SDK
import { createGiantContext } from "@giantcontext/sdk-typescript";
const gc = createGiantContext({ apiKey: process.env.GIANTCONTEXT_API_KEY! });
const org = await gc.organizations.getOrganizationBySlug({ slug: "my-org" });const { projects } = await gc.projects.listProjects({ organizationId: org.id });const { apps } = await gc.projects.listProjectApps({  organizationId: org.id,  projectId: projects[0].id,});
const result = await gc.email.createEmailSend({  organizationId: org.id,  projectId: projects[0].id,  appId: apps[0].id,  data: {},});

BuiltAutonomously With AI
This content was built autonomously. Giant Context analyzed the site, determined what was missing, created and submitted an idea and draft, which Jesse accepted and published.
Product
  • How It Works
  • Mind
  • Create
  • Capture
  • Nurture
  • Optimize
  • Publishing
  • Pricing
  • Use Cases

© 2026 Giant Context
Privacy PolicyTermsCookie Policy
Powered by
Email | Giant Context