curl -X POST https://win.oneshotagent.com/v1/tools/physical-mail/preview \
-H "Content-Type: application/json" \
-H "X-Agent-ID: 0xYourWalletAddress" \
-H "x-agent-proof: <base64 signed proof, scope=write>" \
-d '{
"to": { "name": "Jane Doe", "address_line1": "185 Berry St", "address_city": "San Francisco", "address_state": "CA", "address_zip": "94107" },
"from": { "name": "Acme Inc", "address_line1": "1 Main St", "address_city": "Austin", "address_state": "TX", "address_zip": "78701" },
"artwork": { "kind": "letter", "file": "00000000-0000-4000-8000-000000000000", "color": false, "double_sided": false }
}'
import { OneShot } from "@oneshot-agent/sdk";
const agent = new OneShot({ privateKey: process.env.AGENT_PRIVATE_KEY });
let quote = await agent.physicalMail.preview({
to: { name: "Jane Doe", address_line1: "185 Berry St", address_city: "San Francisco", address_state: "CA", address_zip: "94107" },
from: { name: "Acme Inc", address_line1: "1 Main St", address_city: "Austin", address_state: "TX", address_zip: "78701" },
artwork: { kind: "letter", file: asset.asset_id, color: false, double_sided: false },
});
while (quote.status !== "ready") {
await new Promise((resolve) => setTimeout(resolve, 2000));
quote = await agent.physicalMail.getQuote(quote.quote_id);
}
quote = client.physical_mail.preview({
"to": {"name": "Jane Doe", "address_line1": "185 Berry St", "address_city": "San Francisco", "address_state": "CA", "address_zip": "94107"},
"from": {"name": "Acme Inc", "address_line1": "1 Main St", "address_city": "Austin", "address_state": "TX", "address_zip": "78701"},
"artwork": {"kind": "letter", "file": asset["asset_id"], "color": False, "double_sided": False},
})
{
"quote_id": "00000000-0000-4000-8000-000000000000",
"input": {
"to": { "name": "Jane Doe", "address_line1": "185 BERRY ST", "address_city": "SAN FRANCISCO", "address_state": "CA", "address_zip": "94107", "address_country": "US" },
"from": { "name": "Acme Inc", "address_line1": "1 MAIN ST", "address_city": "AUSTIN", "address_state": "TX", "address_zip": "78701", "address_country": "US" },
"artwork": { "kind": "letter", "file": "00000000-0000-4000-8000-000000000000", "color": false, "double_sided": false }
},
"input_hash": "<64 hex characters>",
"status": "rendering",
"preview": { "url": null, "thumbnails": [] },
"total_usdc": null,
"service_fee_usdc": null,
"expires_at": "2026-10-29T12:30:00.000Z",
"approval_id": null,
"delivery_proves_readership": false
}
{
"error": "address_not_deliverable"
}
Physical Mail
Preview and quote a mailpiece
Render an uncharged test proof and quote a letter or a postcard
POST
/
v1
/
tools
/
physical-mail
/
preview
curl -X POST https://win.oneshotagent.com/v1/tools/physical-mail/preview \
-H "Content-Type: application/json" \
-H "X-Agent-ID: 0xYourWalletAddress" \
-H "x-agent-proof: <base64 signed proof, scope=write>" \
-d '{
"to": { "name": "Jane Doe", "address_line1": "185 Berry St", "address_city": "San Francisco", "address_state": "CA", "address_zip": "94107" },
"from": { "name": "Acme Inc", "address_line1": "1 Main St", "address_city": "Austin", "address_state": "TX", "address_zip": "78701" },
"artwork": { "kind": "letter", "file": "00000000-0000-4000-8000-000000000000", "color": false, "double_sided": false }
}'
import { OneShot } from "@oneshot-agent/sdk";
const agent = new OneShot({ privateKey: process.env.AGENT_PRIVATE_KEY });
let quote = await agent.physicalMail.preview({
to: { name: "Jane Doe", address_line1: "185 Berry St", address_city: "San Francisco", address_state: "CA", address_zip: "94107" },
from: { name: "Acme Inc", address_line1: "1 Main St", address_city: "Austin", address_state: "TX", address_zip: "78701" },
artwork: { kind: "letter", file: asset.asset_id, color: false, double_sided: false },
});
while (quote.status !== "ready") {
await new Promise((resolve) => setTimeout(resolve, 2000));
quote = await agent.physicalMail.getQuote(quote.quote_id);
}
quote = client.physical_mail.preview({
"to": {"name": "Jane Doe", "address_line1": "185 Berry St", "address_city": "San Francisco", "address_state": "CA", "address_zip": "94107"},
"from": {"name": "Acme Inc", "address_line1": "1 Main St", "address_city": "Austin", "address_state": "TX", "address_zip": "78701"},
"artwork": {"kind": "letter", "file": asset["asset_id"], "color": False, "double_sided": False},
})
{
"quote_id": "00000000-0000-4000-8000-000000000000",
"input": {
"to": { "name": "Jane Doe", "address_line1": "185 BERRY ST", "address_city": "SAN FRANCISCO", "address_state": "CA", "address_zip": "94107", "address_country": "US" },
"from": { "name": "Acme Inc", "address_line1": "1 MAIN ST", "address_city": "AUSTIN", "address_state": "TX", "address_zip": "78701", "address_country": "US" },
"artwork": { "kind": "letter", "file": "00000000-0000-4000-8000-000000000000", "color": false, "double_sided": false }
},
"input_hash": "<64 hex characters>",
"status": "rendering",
"preview": { "url": null, "thumbnails": [] },
"total_usdc": null,
"service_fee_usdc": null,
"expires_at": "2026-10-29T12:30:00.000Z",
"approval_id": null,
"delivery_proves_readership": false
}
{
"error": "address_not_deliverable"
}
Overview
Quotes one letter or postcard and renders a proof of it. Nothing is printed or charged. Both addresses are validated first. A letter’s price counts its PDF pages. Free. Rendering can take a moment: the quote comes back withstatus: "rendering" and no price. Poll Get a quote until status is ready, then show preview.url and total_usdc to the person who approves. A quote expires 30 minutes after it is created.
Authentication
X-Agent-ID plus a signed x-agent-proof with scope: "write", or an access token. See proof authentication. 60 requests a minute per agent.
Request Body
object
required
Recipient address:
name, address_line1, address_line2 (optional), address_city, address_state (two letters), address_zip (5 or 9 digits), address_country (optional, US). See Validate an address.object
required
Return address, same shape as
toobject
required
Letter:
{ "kind": "letter", "file": "<asset_id of a PDF>", "color": false, "double_sided": false }. color and double_sided default to false. Postcard: { "kind": "postcard", "front": "<asset_id>", "back": "<asset_id>" }. Asset IDs come from Upload artwork.Response
The quote. Its fields are listed on Get a quote.curl -X POST https://win.oneshotagent.com/v1/tools/physical-mail/preview \
-H "Content-Type: application/json" \
-H "X-Agent-ID: 0xYourWalletAddress" \
-H "x-agent-proof: <base64 signed proof, scope=write>" \
-d '{
"to": { "name": "Jane Doe", "address_line1": "185 Berry St", "address_city": "San Francisco", "address_state": "CA", "address_zip": "94107" },
"from": { "name": "Acme Inc", "address_line1": "1 Main St", "address_city": "Austin", "address_state": "TX", "address_zip": "78701" },
"artwork": { "kind": "letter", "file": "00000000-0000-4000-8000-000000000000", "color": false, "double_sided": false }
}'
import { OneShot } from "@oneshot-agent/sdk";
const agent = new OneShot({ privateKey: process.env.AGENT_PRIVATE_KEY });
let quote = await agent.physicalMail.preview({
to: { name: "Jane Doe", address_line1: "185 Berry St", address_city: "San Francisco", address_state: "CA", address_zip: "94107" },
from: { name: "Acme Inc", address_line1: "1 Main St", address_city: "Austin", address_state: "TX", address_zip: "78701" },
artwork: { kind: "letter", file: asset.asset_id, color: false, double_sided: false },
});
while (quote.status !== "ready") {
await new Promise((resolve) => setTimeout(resolve, 2000));
quote = await agent.physicalMail.getQuote(quote.quote_id);
}
quote = client.physical_mail.preview({
"to": {"name": "Jane Doe", "address_line1": "185 Berry St", "address_city": "San Francisco", "address_state": "CA", "address_zip": "94107"},
"from": {"name": "Acme Inc", "address_line1": "1 Main St", "address_city": "Austin", "address_state": "TX", "address_zip": "78701"},
"artwork": {"kind": "letter", "file": asset["asset_id"], "color": False, "double_sided": False},
})
{
"quote_id": "00000000-0000-4000-8000-000000000000",
"input": {
"to": { "name": "Jane Doe", "address_line1": "185 BERRY ST", "address_city": "SAN FRANCISCO", "address_state": "CA", "address_zip": "94107", "address_country": "US" },
"from": { "name": "Acme Inc", "address_line1": "1 MAIN ST", "address_city": "AUSTIN", "address_state": "TX", "address_zip": "78701", "address_country": "US" },
"artwork": { "kind": "letter", "file": "00000000-0000-4000-8000-000000000000", "color": false, "double_sided": false }
},
"input_hash": "<64 hex characters>",
"status": "rendering",
"preview": { "url": null, "thumbnails": [] },
"total_usdc": null,
"service_fee_usdc": null,
"expires_at": "2026-10-29T12:30:00.000Z",
"approval_id": null,
"delivery_proves_readership": false
}
{
"error": "address_not_deliverable"
}
Errors
| Code | When |
|---|---|
400 invalid_input | See details |
400 letter_requires_pdf | A letter’s file is not a PDF |
404 artwork_not_found | No such asset for this agent |
422 address_not_deliverable | to or from is undeliverable |
422 invalid_letter_pdf, 422 unsupported_letter_length | Unreadable PDF, or not 1 to 60 pages |
503 mail_rate_unavailable | Retry |