curl -X POST https://win.oneshotagent.com/v1/tools/email/send \
-H "Content-Type: application/json" \
-H "X-Quote-ID: quote_abc123" \
-H "payment-signature: <base64 x402 payment>" \
-d '{
"from_address": "[email protected]",
"from_name": "OneShot Team",
"to_address": "[email protected]",
"subject": "Hello from OneShot",
"body": "This is a test email"
}'
# Quote was created without from_address → server-rotated, locked the pick.
# Send replays the locked address automatically.
curl -X POST https://win.oneshotagent.com/v1/tools/email/send \
-H "Content-Type: application/json" \
-H "X-Quote-ID: quote_abc123" \
-H "payment-signature: <base64 x402 payment>" \
-d '{
"to_address": "[email protected]",
"subject": "Hello",
"body": "..."
}'
const response = await fetch(
"https://win.oneshotagent.com/v1/tools/email/send",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Quote-ID": "quote_abc123",
"payment-signature": paymentProof,
},
body: JSON.stringify({
from_address: "[email protected]",
from_name: "OneShot Team",
to_address: "[email protected]",
subject: "Hello from OneShot",
body: "This is a test email",
}),
},
);
{
"request_id": "req_xyz789",
"status": "processing",
"message": "Email job queued successfully"
}
Email
Send an email with automatic domain provisioning
POST
/
v1
/
tools
/
email
/
send
curl -X POST https://win.oneshotagent.com/v1/tools/email/send \
-H "Content-Type: application/json" \
-H "X-Quote-ID: quote_abc123" \
-H "payment-signature: <base64 x402 payment>" \
-d '{
"from_address": "[email protected]",
"from_name": "OneShot Team",
"to_address": "[email protected]",
"subject": "Hello from OneShot",
"body": "This is a test email"
}'
# Quote was created without from_address → server-rotated, locked the pick.
# Send replays the locked address automatically.
curl -X POST https://win.oneshotagent.com/v1/tools/email/send \
-H "Content-Type: application/json" \
-H "X-Quote-ID: quote_abc123" \
-H "payment-signature: <base64 x402 payment>" \
-d '{
"to_address": "[email protected]",
"subject": "Hello",
"body": "..."
}'
const response = await fetch(
"https://win.oneshotagent.com/v1/tools/email/send",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Quote-ID": "quote_abc123",
"payment-signature": paymentProof,
},
body: JSON.stringify({
from_address: "[email protected]",
from_name: "OneShot Team",
to_address: "[email protected]",
subject: "Hello from OneShot",
body: "This is a test email",
}),
},
);
{
"request_id": "req_xyz789",
"status": "processing",
"message": "Email job queued successfully"
}
Sends an email you already quoted. Pass the
quote_id from /email/quote in X-Quote-ID, with an x402 payment proof for its total_cost. The send runs as a job: poll with the returned request_id. On a new domain, OneShot provisions it first, then sends.
Authentication
Requires x402 payment proof in thepayment-signature header.
Headers
string
required
Quote ID from
/email/quote. Must be an unused quote owned by the same
wallet, less than 1 hour old.string
required
Base64-encoded x402 payment payload authorizing the quoted
total_cost.Request body
string
Required when you passed
from_address to /email/quote. Optional when
rotation picked the address: the server uses the address locked into the
quote, and a different value returns 400 from_address_mismatch.string
Sender display name, rendered as
From: From Name <from_address>. Max 100
characters, no newlines or angle brackets.string
relay (default; no mailbox fee) or mailbox (each new from-address adds a
one-time mailbox_provisioning_fee). Set it on
/email/quote, which locks the mode, and omit
it here; mailbox on a live relay domain returns 400 mailbox_mode_conflict.
A provisioned domain keeps its own mode whatever you pass. Check
mailbox_mode per domain on /email/domains.string | string[]
required
Recipient address or addresses. An array sends each recipient a separate
email, not CC or BCC.
string
required
Email subject line
string
required
Email body (plain text)
array
Attachment objects with
filename, content_type, and content (base64)Response
string
Job ID for tracking the send
string
pending, processing, completed, or failedstring
Status message
string
Advisory; the send still proceeds.
pinned_domain_warming: the pinned domain
is still warming. pinned_over_limit: it is over today’s daily_send_limit.
Only rotation enforces the limit and warmup score.curl -X POST https://win.oneshotagent.com/v1/tools/email/send \
-H "Content-Type: application/json" \
-H "X-Quote-ID: quote_abc123" \
-H "payment-signature: <base64 x402 payment>" \
-d '{
"from_address": "[email protected]",
"from_name": "OneShot Team",
"to_address": "[email protected]",
"subject": "Hello from OneShot",
"body": "This is a test email"
}'
# Quote was created without from_address → server-rotated, locked the pick.
# Send replays the locked address automatically.
curl -X POST https://win.oneshotagent.com/v1/tools/email/send \
-H "Content-Type: application/json" \
-H "X-Quote-ID: quote_abc123" \
-H "payment-signature: <base64 x402 payment>" \
-d '{
"to_address": "[email protected]",
"subject": "Hello",
"body": "..."
}'
const response = await fetch(
"https://win.oneshotagent.com/v1/tools/email/send",
{
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Quote-ID": "quote_abc123",
"payment-signature": paymentProof,
},
body: JSON.stringify({
from_address: "[email protected]",
from_name: "OneShot Team",
to_address: "[email protected]",
subject: "Hello from OneShot",
body: "This is a test email",
}),
},
);
{
"request_id": "req_xyz789",
"status": "processing",
"message": "Email job queued successfully"
}
Domain provisioning
For a new domain, OneShot registers it, configures DNS, sets up sending and verifies ownership. This takes 2-5 minutes; the email goes out when provisioning completes.Errors
| Code | When |
|---|---|
400 from_address_mismatch | from_address doesn’t match the address locked into the quote by rotation. Omit it or pass the locked value. |
400 missing_from_address | The quote was created with an explicit from_address and the send has none. |
400 quote_already_used | A previous send already used the quote. |
503 moderation_unavailable | The content moderation provider could not be reached; nothing was sent and a settled payment is returned as credit. Retry after Retry-After. |
402 mailbox_provisioning_required | from_address is a new address on a domain that provisions a mailbox per address, and the paid quote didn’t include the one-time mailbox_provisioning_fee. Re-quote with this exact from_address, pay, and retry. |
403 domain_not_owned | The domain in from_address belongs to a different agent. |