Create a transactional email
This creates a transactional email and a related draft email message in one request.
Only a name value is required.
Save the returned draftEmailMessageContentRevisionId. Pass it as
expectedRevisionId when updating the draft email message to avoid 409 Conflict errors caused by stale revisions.
API reference
const response = await fetch ( "https://app.loops.so/api/v1/transactional-emails" , {
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
name: "Password reset" ,
}),
});
const data = await response . json ();
const transactionalId = data . id ;
const draftEmailMessageId = data . draftEmailMessageId ;
const draftEmailMessageContentRevisionId =
data . draftEmailMessageContentRevisionId ;
Query themes and components for your LMX
You can fetch your available themes and reusable components before building
the lmx payload.
List themes API reference
List components API reference
const [ themesResponse , componentsResponse ] = await Promise . all ([
fetch ( "https://app.loops.so/api/v1/themes?perPage=20" , {
method: "GET" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
},
}),
fetch ( "https://app.loops.so/api/v1/components?perPage=20" , {
method: "GET" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
},
}),
]);
const themes = await themesResponse . json ();
const components = await componentsResponse . json ();
Update the draft email message with contentRevisionId
Use draftEmailMessageId from when you created the transactional as the path parameter, and pass draftEmailMessageContentRevisionId as expectedRevisionId.
Apply styles or a theme in <Style />, and build the email using LMX elements.
Themes and components you queried in the previous step can be referenced by their IDs.
Save the returned contentRevisionId after each update. Pass it as
expectedRevisionId on the next update to avoid 409 Conflict errors caused
by stale revisions.
API reference
Get theme API reference
Get component API reference
const lmxContent = `
<Style themeId="default" />
<Paragraph>
<Text>Click the link below to reset your password.</Text>
</Paragraph>
<Component componentId="logo" />
<Section>
...
</Section>` ;
const response = await fetch (
`https://app.loops.so/api/v1/email-messages/ ${ draftEmailMessageId } ` ,
{
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
expectedRevisionId: draftEmailMessageContentRevisionId ,
subject: "Reset your password" ,
previewText: "Your password reset link" ,
fromName: "Loops" ,
fromEmail: "hello" ,
replyToEmail: "support@example.com" ,
lmx: lmxContent ,
}),
},
);
const updated = await response . json ();
const nextContentRevisionId = updated . contentRevisionId ;
Upload an image asset
If your LMX includes <Image /> tags, upload image files with the Upload API
and use the returned finalUrl as the image src.
Create upload API reference
Complete upload API reference
const createResponse = await fetch ( "https://app.loops.so/api/v1/uploads" , {
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
contentType: "image/png" ,
contentLength: imageBuffer . byteLength ,
}),
});
const { emailAssetId , presignedUrl } = await createResponse . json ();
await fetch ( presignedUrl , {
method: "PUT" ,
headers: {
"Content-Type" : "image/png" ,
"Content-Length" : String ( imageBuffer . byteLength ),
},
body: imageBuffer ,
});
const completeResponse = await fetch (
`https://app.loops.so/api/v1/uploads/ ${ emailAssetId } /complete` ,
{
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
},
},
);
const { finalUrl } = await completeResponse . json ();
Publish the transactional email
Publish the draft email message so it can be sent with the transactional send endpoint.
API reference
const publishResponse = await fetch (
`https://app.loops.so/api/v1/transactional-emails/ ${ transactionalId } /publish` ,
{
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
},
},
);
const published = await publishResponse . json ();
Send a transactional email
Use the transactional id from create (or publish) as transactionalId in the send request.
API reference
JavaScript
JavaScript SDK
PHP SDK
Ruby SDK
Python
await fetch ( "https://app.loops.so/api/v1/transactional" , {
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
email: "test@example.com" ,
transactionalId: transactionalId ,
dataVariables: {
loginUrl: "https://example.com/login" ,
},
}),
});
Send a transactional email with an array data variable
Learn more about arrays .
API reference
JavaScript
JavaScript SDK
PHP SDK
Ruby SDK
Python
await fetch ( "https://app.loops.so/api/v1/transactional" , {
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
email: "test@example.com" ,
transactionalId: "<transactional-id>" ,
dataVariables: {
items: [
{ name: "Item 1" , description: "Description of Item 1" },
{ name: "Item 2" , description: "Description of Item 2" },
],
},
}),
});
Send a transactional email with attachments
You must request attachments to be enabled in your account before you can send emails with them.
API reference
JavaScript
JavaScript SDK
PHP SDK
Ruby SDK
Python
await fetch ( "https://app.loops.so/api/v1/transactional" , {
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
"Content-Type" : "application/json" ,
},
body: JSON . stringify ({
email: "test@example.com" ,
transactionalId: "<transactional-id>" ,
dataVariables: {
loginUrl: "https://example.com/login" ,
},
attachments: [
{
filename: "example.pdf" ,
contentType: "application/pdf" ,
data: "<base64-encoded-file-content>" ,
},
],
}),
});
Send a transactional email with an idempotency key
Add an Idempotency-Key header to the request to prevent duplicate requests.
API reference
JavaScript
JavaScript SDK
PHP SDK
Ruby SDK
Python
await fetch ( "https://app.loops.so/api/v1/transactional" , {
method: "POST" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
"Content-Type" : "application/json" ,
"Idempotency-Key" : "550e8400-e29b-41d4-a716-446655440000" ,
},
body: JSON . stringify ({
email: "test@example.com" ,
transactionalId: "<transactional-id>" ,
dataVariables: {
loginUrl: "https://example.com/login" ,
},
}),
});
List transactional emails
API reference
JavaScript
JavaScript SDK
PHP SDK
Ruby SDK
Python
await fetch ( "https://app.loops.so/api/v1/transactional-emails" , {
method: "GET" ,
headers: {
"Authorization" : "Bearer <your-api-key>" ,
},
});