Send email
curl --request POST \
--url http://api.gu1.ai/marketplace/messaging/send-email \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "<string>",
"fromEmail": "<string>",
"fromSenderId": {},
"templateParams": {},
"templateId": {},
"subject": "<string>",
"htmlBody": "<string>",
"textBody": "<string>"
}
'import requests
url = "http://api.gu1.ai/marketplace/messaging/send-email"
payload = {
"to": "<string>",
"fromEmail": "<string>",
"fromSenderId": {},
"templateParams": {},
"templateId": {},
"subject": "<string>",
"htmlBody": "<string>",
"textBody": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '<string>',
fromEmail: '<string>',
fromSenderId: {},
templateParams: {},
templateId: {},
subject: '<string>',
htmlBody: '<string>',
textBody: '<string>'
})
};
fetch('http://api.gu1.ai/marketplace/messaging/send-email', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "http://api.gu1.ai/marketplace/messaging/send-email",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '<string>',
'fromEmail' => '<string>',
'fromSenderId' => [
],
'templateParams' => [
],
'templateId' => [
],
'subject' => '<string>',
'htmlBody' => '<string>',
'textBody' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://api.gu1.ai/marketplace/messaging/send-email"
payload := strings.NewReader("{\n \"to\": \"<string>\",\n \"fromEmail\": \"<string>\",\n \"fromSenderId\": {},\n \"templateParams\": {},\n \"templateId\": {},\n \"subject\": \"<string>\",\n \"htmlBody\": \"<string>\",\n \"textBody\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://api.gu1.ai/marketplace/messaging/send-email")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"<string>\",\n \"fromEmail\": \"<string>\",\n \"fromSenderId\": {},\n \"templateParams\": {},\n \"templateId\": {},\n \"subject\": \"<string>\",\n \"htmlBody\": \"<string>\",\n \"textBody\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://api.gu1.ai/marketplace/messaging/send-email")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"<string>\",\n \"fromEmail\": \"<string>\",\n \"fromSenderId\": {},\n \"templateParams\": {},\n \"templateId\": {},\n \"subject\": \"<string>\",\n \"htmlBody\": \"<string>\",\n \"textBody\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodyAPI Reference
Send email
POST /marketplace/messaging/send-email — transactional email with optional template or inline HTML — through the gu1 messaging API for customer communications.
POST
/
marketplace
/
messaging
/
send-email
Send email
curl --request POST \
--url http://api.gu1.ai/marketplace/messaging/send-email \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"to": "<string>",
"fromEmail": "<string>",
"fromSenderId": {},
"templateParams": {},
"templateId": {},
"subject": "<string>",
"htmlBody": "<string>",
"textBody": "<string>"
}
'import requests
url = "http://api.gu1.ai/marketplace/messaging/send-email"
payload = {
"to": "<string>",
"fromEmail": "<string>",
"fromSenderId": {},
"templateParams": {},
"templateId": {},
"subject": "<string>",
"htmlBody": "<string>",
"textBody": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
to: '<string>',
fromEmail: '<string>',
fromSenderId: {},
templateParams: {},
templateId: {},
subject: '<string>',
htmlBody: '<string>',
textBody: '<string>'
})
};
fetch('http://api.gu1.ai/marketplace/messaging/send-email', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "http://api.gu1.ai/marketplace/messaging/send-email",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'to' => '<string>',
'fromEmail' => '<string>',
'fromSenderId' => [
],
'templateParams' => [
],
'templateId' => [
],
'subject' => '<string>',
'htmlBody' => '<string>',
'textBody' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "http://api.gu1.ai/marketplace/messaging/send-email"
payload := strings.NewReader("{\n \"to\": \"<string>\",\n \"fromEmail\": \"<string>\",\n \"fromSenderId\": {},\n \"templateParams\": {},\n \"templateId\": {},\n \"subject\": \"<string>\",\n \"htmlBody\": \"<string>\",\n \"textBody\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("http://api.gu1.ai/marketplace/messaging/send-email")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"to\": \"<string>\",\n \"fromEmail\": \"<string>\",\n \"fromSenderId\": {},\n \"templateParams\": {},\n \"templateId\": {},\n \"subject\": \"<string>\",\n \"htmlBody\": \"<string>\",\n \"textBody\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("http://api.gu1.ai/marketplace/messaging/send-email")
http = Net::HTTP.new(url.host, url.port)
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"to\": \"<string>\",\n \"fromEmail\": \"<string>\",\n \"fromSenderId\": {},\n \"templateParams\": {},\n \"templateId\": {},\n \"subject\": \"<string>\",\n \"htmlBody\": \"<string>\",\n \"textBody\": \"<string>\"\n}"
response = http.request(request)
puts response.read_bodySends a single transactional email for the authenticated organization. Requires the Email marketplace integration and a configured messaging provider. See Messaging overview for prerequisites, billing, and senders.
If you omit both Custom sender (
When you send
Example rejection (unverified domain):
Do not send
You must provide at least one of
Exact fields may match your
After validation, the MS Provider may still return
Endpoint
POST https://api.gu1.ai/marketplace/messaging/send-email
Headers
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
X-Organization-ID: <uuid> # optional; multi-org session users
Request body
Common
string
required
Recipient email address.
string
Full From address (e.g.
noreply@your-domain.com). The domain must be registered and verified for your organization under Settings → Email → Domains. You do not need a matching row under Senders when the domain is already verified. Mutually exclusive with fromSenderId.string (UUID)
ID of a sender from Settings → Email → Senders. Mutually exclusive with
fromEmail.fromEmail and fromSenderId, the API uses the platform default Gu1 sender. That is expected behavior, not an error.
Custom sender (fromEmail)
When you send fromEmail, for example example@my-domain.com, the API validates the domain (my-domain.com) before attempting delivery. The response is always 400 with { "success": false, "error": "<English message>" }; the email is not sent until the domain is verified.
| Situation | API response |
|---|---|
| Domain never added in Gu1 for your org | Domain "my-domain.com" is not registered in Gu1. Add and verify it under Settings → Email → Domains before using sender "example@my-domain.com". |
| Domain exists in Gu1 but DNS not verified yet | Domain "my-domain.com" is not verified yet. Complete DNS records and click Verify under Settings → Email → Domains. |
| Domain verified | Request continues; any local part on that domain is allowed (example@…, noreply@…, etc.) without a Senders row. If the address exists in Senders, its display name is used. |
{
"success": false,
"error": "Domain \"my-domain.com\" is not verified yet. Complete DNS records and click Verify under Settings → Email → Domains."
}
object
Key-value map for
{{placeholders}} in subject, htmlBody, textBody, or in a stored template. Values may be strings, numbers, or booleans (coerced for rendering). Default {}.Mode A — Stored template
string (UUID)
required
ID of a message template with channel email (org or system template).
htmlBody or textBody in this mode.
string
Optional fallback if the template has no subject or the subject is empty after placeholder replacement.
Mode B — Inline content
Do not sendtemplateId.
string
required
Email subject. May contain
{{variables}} replaced via templateParams.string
HTML body. Max ~500,000 characters. May include
{{variables}}.string
Plain-text body; used as multipart alternative when both HTML and text are sent, or converted to minimal HTML if HTML is omitted. Max ~500,000 characters. May include
{{variables}}.htmlBody or textBody.
Example — template
curl -X POST https://api.gu1.ai/marketplace/messaging/send-email \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"templateId": "550e8400-e29b-41d4-a716-446655440000",
"templateParams": { "name": "Ada", "token": "482910" },
"fromEmail": "noreply@yourdomain.com"
}'
Example — inline HTML + placeholders
curl -X POST https://api.gu1.ai/marketplace/messaging/send-email \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"subject": "Your code: {{token}}",
"htmlBody": "<p>Hello, your code is <strong>{{token}}</strong></p>",
"templateParams": { "token": "482910" }
}'
Example — plain text only
curl -X POST https://api.gu1.ai/marketplace/messaging/send-email \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "user@example.com",
"subject": "Notification",
"textBody": "Line one\nLine two"
}'
Success response
{
"success": true,
"messageId": "provider-message-id"
}
MessageDeliveryService / provider response.
Errors and HTTP status
Business and validation responses from this route use JSON like{ "success": false, "error": "<English message>" } unless noted. All error strings are in English. Invalid JSON bodies may return a different shape from the validator (e.g. Zod field issues) at 400.
| Situation | Typical status | Example error (or note) |
|---|---|---|
| Email integration off for the org | 400 | Email integration is not active. Enable Email (global_sender_email) in Applications (Marketplace) for this organization. |
| Messaging provider URL not set (server) | 400 | MS_PROVIDER_URL is not configured on the server. Configure the messaging provider to send email. |
| Cost > 0 and no pack quota / credits | 400 | Insufficient balance for this send (cost … credits). Add tokens… (see response for full text) |
| Send succeeded but billing failed | 400 | Insufficient balance to record billing for this send. Current balance (…) is below required (…). … |
Both templateId and inline body | 400 (validation) | Use either templateId + templateParams, or htmlBody/textBody only — not both. |
| Neither template nor body | 400 (validation) | Provide templateId or htmlBody/textBody. |
Inline mode without subject | 400 (validation) | subject is required when not using a template. |
| Template UUID wrong / other org | 404 | Template not found or not accessible for this organization. |
| Template exists but not email channel | 400 | Template channel is "<channel>"; email is required. |
| Template + empty subject after render | 400 | The template has no subject or it is empty after replacing variables. Send subject in the request body or set the subject on the template. |
Both fromSenderId and fromEmail | 400 | Send only one of fromSenderId or fromEmail, not both. |
Unknown fromSenderId | 400 | fromSenderId does not match a sender for this organization. Check Settings → Email → Senders. |
fromEmail domain not registered for the org | 400 | Domain "…" is not registered in Gu1. Add and verify it under Settings → Email → Domains before using sender "…". |
| Domain registered but DNS not verified | 400 | Domain "…" is not verified yet. Complete DNS records and click Verify under Settings → Email → Domains. |
Empty inline subject after {{…}} | 400 | Subject is empty after replacing variables. |
| Empty body after render | 400 | htmlBody or textBody is empty after rendering. |
| No session org | 401 | { "error": "Organization ID not found" } (no success field) |
{ "success": false, "error": "…" } (e.g. provider rejection) at 200 or an error status depending on implementation—inspect success and error on every response.Was this page helpful?