Manage email campaigns, templates, recipients, and tracking.
Send transactional email
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/actions/sendSends a single transactional email to a specific recipient using an email template. Used for one-off emails like order confirmations, password resets, etc.
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 one contact's sent and planned emails with per-send opens and clicks
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/contacts/{contactId}/timelineReturns 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.
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 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.
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 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.
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"});
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.
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 email recipient
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipients/{recipientId}Returns a single recipient row with subscription state.
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",});
Unsubscribe a contact from one email; the row is kept for resubscribe
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipients/{recipientId}/unsubscribeSoft-unsubscribes a recipient by setting unsubscribed_at and an optional reason. The row is preserved for audit + resubscribe.
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: {}});
List one email's subscribers, including past unsubscribes, newest subscription first
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipientsReturns the subscribers for a specific email template. Includes currently subscribed and previously unsubscribed contacts.
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",});
Subscribe a CRM contact to one email; resubscribes if previously unsubscribed
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emails/{emailId}/recipientsAdds a contact as a recipient of this email. If the contact was previously unsubscribed, the row is resurrected (unsubscribed_at cleared).
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});\nList emails in an email app, newest first; pass lite=true to skip content
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/emailsReturns 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.
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 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.
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 email header
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/headers/{headerId}Permanently deletes an email header.
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,});
List headers in an email app, newest first; pass lite=true to skip content
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/headersReturns a list of all email headers for the specified app. Headers contain branding and navigation elements prepended to emails.
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,});
Create a header shell; only name is required, add blocks afterwards
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/headersCreates a new email header with content blocks for branding and navigation.
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 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).
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",});
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'.
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: {},});
List past, queued and planned sends across the app, filterable by email or contact
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/sendsReturns 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.
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,});
Create a send for one contact; defaults to planned, which sends nothing until queued
/organizations/{organizationId}/projects/{projectId}/apps/email/{appId}/sendsCreates 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.
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: {},});