PieterPost MCP Server
PieterPost lets AI agents prepare, price, review, pay for, and send real letters and postcards through a safe OAuth-powered MCP server.
Documentation
MCP Markdown reference
This is the same markdown returned from the public MCP docs URL for agents.
Markdown-only URL
https://pieterpost.com/api/docs/mcp.md
Markdown
# PieterPost MCP docs
Docs page: https://pieterpost.com/api/docs/mcp
Source: https://pieterpost.com/api/docs/mcp.md
MCP server URL: `https://pieterpost.com/mcp/`
Protocol version: `2025-11-25`
Supported protocol versions: `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`
Server version: `2026.05.03.1`
This is the markdown-only reference for agents and MCP clients that connect to PieterPost. Use it for tool descriptions, input types, OAuth details, safety rules, and examples.
## Client setup
PieterPost exposes a remote MCP server with OAuth authorization code, PKCE, dynamic client registration, short-lived bearer tokens, refresh tokens, and revocation.
```json
{
"allowed_tools": [
"search",
"fetch",
"list_mailbook_contacts",
"get_mailbook_contact",
"create_mailbook_contact",
"update_mailbook_contact",
"delete_mailbook_contact",
"quote_order",
"upload_asset",
"create_compose_link",
"create_payment_link",
"create_checkout_link",
"create_direct_order",
"get_wallet",
"get_order",
"get_topup",
"list_topups",
"create_credit_topup",
"list_api_keys",
"create_api_key",
"revoke_api_key"
],
"require_approval": {
"never": {
"read_only": true
}
},
"server_label": "pieterpost",
"server_url": "https://pieterpost.com/mcp/",
"type": "mcp"
}
OAuth and metadata
- OAuth issuer:
https://pieterpost.com/mcp/oauth - Protected resource metadata:
https://pieterpost.com/.well-known/oauth-protected-resource/mcp/ - Protected resource convenience URL:
https://pieterpost.com/mcp/.well-known/oauth-protected-resource/ - Authorization server metadata:
https://pieterpost.com/.well-known/oauth-authorization-server/mcp/oauth/ - Authorization server issuer-relative metadata:
https://pieterpost.com/mcp/oauth/.well-known/oauth-authorization-server/ - Dynamic client registration:
https://pieterpost.com/mcp/oauth/register/ - Token endpoint:
https://pieterpost.com/mcp/oauth/token/ - Revocation endpoint:
https://pieterpost.com/mcp/oauth/revoke/ - Bearer challenges use
realm="PieterPost MCP"and pointresource_metadataat the protected resource metadata URL. - Supported scopes:
api:read,api:send,api:keys,mailbook:read,mailbook:write. api:readpermitssearch,fetch,get_wallet, andget_order.api:readalso permitsquote_order,get_topup, andlist_topups.api:sendpermits uploads, compose links, payment links, checkout links, direct orders, and credit top-ups.api:keyspermits listing, creating, and revoking public API keys.mailbook:readpermits listing, searching, and fetching saved Mailbook contacts.mailbook:writepermits creating, updating, and deleting saved Mailbook contacts.
Safety model
- Test mode is the default for writable tools unless
mode: "live"is provided. - Hosted payment and checkout links do not send mail until checkout is paid.
- Live
create_direct_ordersends real mail and spends wallet credits. Only call it after explicit user confirmation, and includeconfirmLiveSend: trueplusmaxAmountCentsgreater than or equal to the calculated total. - Before
create_payment_link,create_checkout_link, orcreate_direct_order, review the exact final letter or postcard text in the payload, including line breaks and any template placeholders or recipient customFields. - API key creation returns the secret once. Existing key secrets cannot be fetched later.
- Uploads accept
fileBase64or a public HTTPSfileUrl; localhost, private network, and metadata host URLs are rejected. - The example OpenAI configuration skips approval only for
readOnlyHinttools. Keep host approval enabled for write tools unless the user has explicitly chosen otherwise. - Use
idempotencyKeyon every create operation. This is especially important for live direct sends, checkout links, and wallet top-ups.
Mail payload parity
MCP order tools accept the same letter and postcard payloads as the public API, with idempotencyKey passed in the tool arguments instead of an HTTP header.
- Letters use
requestType: "letter"and alettersarray. Up to 25 letters are allowed per request. - Each letter can include a
message, up to 3letter-attachmentasset IDs, or both. In letter template mode,templateMessagecan supply the shared message for each recipient. - Letter template mode uses
composeMode: "template",templateMessage, optionalvariableKeys, and recipientcustomFields. - Letter stamp images use
upload_assetwithkind: "letter-stamp-image", thenstampImageAssetIdon the order tool. - Postcards use
requestType: "postcard"and apostcardobject withrecipientorrecipients. Up to 25 postcard recipients are allowed per request. - Postcards can use the default front image or an uploaded custom one. Custom postcard fronts must be square, with a 1:1 aspect ratio. For a custom front, use
upload_assetwithkind: "postcard-image", then pass the returned asset aspostcard.frontImageAssetId. - Hosted checkout tools default to
paymentMethod: "auto". For EUR letter or postcard payment links and EUR wallet top-ups, auto offers both card and iDEAL in Stripe Checkout. PasspaymentMethod: "card"orpaymentMethod: "ideal"only when the user explicitly wants one method. - Recipients can use
addressLines, or structured address fields such asstreetAddress,street,number,postalCode,city,state, andcountry. Free-form address parsing is not performed. - Metadata accepts up to 20 string, number, or boolean values.
Mailbook contacts
- Use
list_mailbook_contactswith a query when the user names a saved contact, for exampleEric. - Use
get_mailbook_contactwhen you already have a contact id. - Contact results include a
recipientobject that can be passed directly intoquote_order,create_payment_link,create_checkout_link,create_direct_order, orcreate_compose_link. - Use
create_mailbook_contact,update_mailbook_contact, anddelete_mailbook_contactfor contact CRUD. Address input must be structured; free-form address parsing is not performed. - Example flow: if the user says,
send a postcard to Bart, calllist_mailbook_contactswithquery: "Bart"; if exactly one contact matches, use that contact'srecipientobject inquote_order, then continue withcreate_payment_link,create_compose_link,create_checkout_link, orcreate_direct_orderdepending on the user's intent and confirmation. If multiple contacts match, ask the user which Bart they mean before creating mail.
Default live send flow
- Do not call
create_api_keyunless the user explicitly asked for a public API key. MCP uses internal action keys automatically. - Call
quote_orderwith the final letter or postcard payload. - Review the exact final text that will be sent, including line breaks and any template variables or customFields.
- Call
create_payment_linkwithmode: "live"and a stableidempotencyKey.senderEmailis optional; Stripe Checkout collects the payer email when omitted.returnUrlis optional; PieterPost uses a hosted MCP return page when it is omitted, localized bylocaleand labeled as a letter or postcard. - Send the returned
paymentLinkUrlto the user. PreferpaymentLinkUrl/publicCheckoutUrlover the raw StripecheckoutUrlwhen both are present. PieterPost sends the mail only after Stripe confirms checkout payment. - Keep the API/credit path available when the user asks for API keys, wallet credits, top-ups, direct send, or an automated trusted workflow:
get_wallet,quote_order,create_credit_topupif needed, thencreate_direct_orderafter explicit confirmation.
Tools summary
search: Search PieterPost API docs and the authenticated API account summary, keys, wallets, orders, activity, and MCP connections.fetch: Fetch a PieterPost API document or account resource returned by the search tool.list_mailbook_contacts: List or search saved Mailbook contacts for the authenticated PieterPost user. Use query for name, email, or address searches. Each result includes a recipient object that can be passed into letter or postcard payloads.get_mailbook_contact: Fetch one saved Mailbook contact by id. The result includes a recipient object for letter or postcard payloads.create_mailbook_contact: Create a saved Mailbook contact for later letter or postcard sending. Requires structured address fields; free-form address parsing is not performed.update_mailbook_contact: Update a saved Mailbook contact. Provide contactId and only the fields to change; omitted fields keep their existing values.delete_mailbook_contact: Delete one saved Mailbook contact by id.create_compose_link: Create a PieterPost compose link for one prepared recipient and optional message. The user reviews, edits, and pays in PieterPost.quote_order: Validate and price a letter or postcard payload without creating an order. Provide exactly one of letters or postcard. Use this before live direct-send flows to confirm the amount, wallet balance gap, and next action.create_payment_link: Create a hosted payment link for one-off MCP letter or postcard sending without public API keys or wallet credits. Provide exactly one of letters or postcard. Mail is sent only after checkout is paid. senderEmail is optional; Stripe Checkout collects the payer email when omitted. returnUrl is optional; PieterPost provides a hosted return page when omitted. Review the final message text before creating the link.create_checkout_link: Create a hosted checkout link for letters or postcards. This is the public-API-compatible name for create_payment_link. Provide exactly one of letters or postcard. Supports bulk letters, letter template mode, custom letter stamps, bulk postcard recipients up to 25 recipients, letter attachments, and optional square 1:1 custom postcard front images. Mail is sent only after checkout is paid. senderEmail is optional for MCP calls; Stripe Checkout collects the payer email when omitted. returnUrl is optional for MCP calls. Review the final message text before creating the link.create_direct_order: Create a direct-send order paid from wallet credits. Provide exactly one of letters or postcard. Supports bulk letters and postcards with the same payload shape as hosted checkout. Test mode simulates sending. Live mode sends real mail and requires confirmLiveSend=true plus maxAmountCents >= the calculated total. Review the final message text before sending.upload_asset: Upload a square 1:1 postcard front image, letter attachment, or custom letter stamp for later use in create_checkout_link or create_direct_order. Provide exactly one of fileBase64 or a public HTTPS fileUrl. Returns an assetId that can be passed as postcard.frontImageAssetId, stampImageAssetId, or in a letter attachments array.get_wallet: Read the API wallet balance and account capability flags for test or live mode.get_order: Fetch a PieterPost API order by id, including hosted checkout/direct-send status, recipient count, amount, and error details.get_topup: Fetch a PieterPost wallet top-up by id, including payment status and checkout URL when still pending.list_topups: List recent PieterPost wallet top-ups for this account. Use mode and currency filters to inspect the active live or test funding history.create_credit_topup: Create a test credit top-up immediately, or create a live Stripe checkout URL for adding API credits used by direct-send orders. paymentMethod=auto is the default; for EUR top-ups it offers both card and iDEAL. Pass paymentMethod=card or paymentMethod=ideal only when the user wants to force one method.list_api_keys: List API key metadata for this PieterPost API account. Secrets are never returned.create_api_key: Create a new PieterPost public API key. The secret is returned once and cannot be recovered later.revoke_api_key: Revoke an existing PieterPost public API key by id.
Tool input schemas
The following JSON is the authoritative MCP tools/list schema exposed by PieterPost.
The schema is intentionally flattened for Codex-style clients, so allowed values and constraints are described in text instead of unsupported JSON Schema keywords such as enum, format, or nested unions.
{
"tools": [
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "Search PieterPost API docs and the authenticated API account summary, keys, wallets, orders, activity, and MCP connections.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"query": {
"description": "Search query.",
"type": "string"
}
},
"required": [
"query"
],
"type": "object"
},
"name": "search",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "Fetch a PieterPost API document or account resource returned by the search tool.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"id": {
"description": "Document id returned by search.",
"type": "string"
}
},
"required": [
"id"
],
"type": "object"
},
"name": "fetch",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "List or search saved Mailbook contacts for the authenticated PieterPost user. Use query for name, email, or address searches. Each result includes a recipient object that can be passed into letter or postcard payloads.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"limit": {
"description": "Maximum number of contacts to return. Defaults to 25; maximum 100.",
"type": "number"
},
"query": {
"description": "Optional search query, such as a contact name, email, city, or street.",
"type": "string"
}
},
"type": "object"
},
"name": "list_mailbook_contacts",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "Fetch one saved Mailbook contact by id. The result includes a recipient object for letter or postcard payloads.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"contactId": {
"description": "Mailbook contact id.",
"type": "string"
}
},
"required": [
"contactId"
],
"type": "object"
},
"name": "get_mailbook_contact",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Create a saved Mailbook contact for later letter or postcard sending. Requires structured address fields; free-form address parsing is not performed.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"birthday": {
"description": "Optional birthday in YYYY-MM-DD format.",
"type": "string"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"displayName": {
"description": "Saved contact display name.",
"type": "string"
},
"email": {
"description": "Optional contact email.",
"type": "string"
},
"extra": {
"description": "Optional address extra line, such as apartment, company, or care-of details.",
"type": "string"
},
"houseNumber": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"description": "State, province, region, or subdivision when applicable.",
"type": "string"
},
"street": {
"type": "string"
}
},
"required": [
"displayName",
"street",
"houseNumber",
"postalCode",
"city",
"country"
],
"type": "object"
},
"name": "create_mailbook_contact",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Update a saved Mailbook contact. Provide contactId and only the fields to change; omitted fields keep their existing values.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"contactId": {
"description": "Mailbook contact id.",
"type": "string"
},
"birthday": {
"description": "Optional birthday in YYYY-MM-DD format.",
"type": "string"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"displayName": {
"description": "Saved contact display name.",
"type": "string"
},
"email": {
"description": "Optional contact email.",
"type": "string"
},
"extra": {
"description": "Optional address extra line, such as apartment, company, or care-of details.",
"type": "string"
},
"houseNumber": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"description": "State, province, region, or subdivision when applicable.",
"type": "string"
},
"street": {
"type": "string"
}
},
"required": [
"contactId"
],
"type": "object"
},
"name": "update_mailbook_contact",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": true,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Delete one saved Mailbook contact by id.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"contactId": {
"description": "Mailbook contact id.",
"type": "string"
}
},
"required": [
"contactId"
],
"type": "object"
},
"name": "delete_mailbook_contact",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Create a PieterPost compose link for one prepared recipient and optional message. The user reviews, edits, and pays in PieterPost.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"externalId": {
"description": "Your correlation id for the created order/link.",
"type": "string"
},
"idempotencyKey": {
"description": "Stable idempotency key for retries. Always include this for create operations, especially in live mode.",
"type": "string"
},
"locale": {
"description": "Locale. Allowed values: \"de\", \"en\", \"es\", \"fr\", \"it\", or \"nl\".",
"type": "string"
},
"message": {
"description": "Prepared message. Trimmed to 6,000 characters.",
"type": "string"
},
"metadata": {
"additionalProperties": true,
"description": "Up to 20 string, number, or boolean values copied to the order/link.",
"type": "object"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"required": [
"recipient"
],
"type": "object"
},
"name": "create_compose_link",
"outputSchema": {
"additionalProperties": false,
"properties": {
"expiresAt": {
"type": "string"
},
"id": {
"type": "string"
},
"mode": {
"const": "compose_link",
"type": "string"
},
"testMode": {
"type": "boolean"
},
"url": {
"type": "string"
}
},
"required": [
"expiresAt",
"id",
"mode",
"testMode",
"url"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "Validate and price a letter or postcard payload without creating an order. Provide exactly one of letters or postcard. Use this before live direct-send flows to confirm the amount, wallet balance gap, and next action.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"composeMode": {
"description": "Letter compose mode. Allowed values: \"personal\" or \"template\". personal uses each letter.message; template uses templateMessage and recipient customFields to generate each letter.",
"type": "string"
},
"externalId": {
"description": "Your correlation id for the created order/link.",
"type": "string"
},
"idempotencyKey": {
"description": "Stable idempotency key for retries. Always include this for create operations, especially in live mode.",
"type": "string"
},
"letters": {
"description": "Bulk letters. Maximum 25.",
"items": {
"additionalProperties": false,
"description": "One letter for one recipient. In personal mode include a message, uploaded attachments, or both. In template mode, templateMessage can supply the message for every recipient. Destination page limits apply to the combined message and attachment pages.",
"properties": {
"attachments": {
"description": "Letter attachment asset IDs or upload_asset objects. Assets must be kind letter-attachment.",
"items": {
"description": "Attachment asset ID string or upload_asset-style object with assetId."
},
"type": "array"
},
"message": {
"description": "Letter body. Trimmed to 6,000 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"required": [
"recipient"
],
"type": "object"
},
"type": "array"
},
"locale": {
"description": "Locale. Allowed values: \"de\", \"en\", \"es\", \"fr\", \"it\", or \"nl\".",
"type": "string"
},
"metadata": {
"additionalProperties": true,
"description": "Up to 20 string, number, or boolean values copied to the order/link.",
"type": "object"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"postcard": {
"additionalProperties": false,
"description": "Postcard payload. Provide recipient for one card or recipients for bulk cards up to 25 recipients. Add frontImageAssetId or frontImage when you want a square 1:1 custom front instead of the default one.",
"properties": {
"composeMode": {
"description": "Compose mode. Allowed values: \"personal\" or \"template\". personal sends one message as written; template lets recipient customFields replace variables in supported templates.",
"type": "string"
},
"frontImage": {
"description": "Optional square 1:1 postcard image asset ID string or upload_asset-style object. Equivalent to frontImageAssetId."
},
"frontImageAssetId": {
"description": "Optional asset ID returned by upload_asset for a square 1:1 postcard-image.",
"type": "string"
},
"message": {
"description": "Postcard message. Trimmed to 1,200 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"recipients": {
"description": "Bulk postcard recipients. Maximum 25.",
"items": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array"
},
"variableKeys": {
"description": "Template variable keys to use for postcard personalization.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"requestType": {
"description": "Request type. Allowed values: \"letter\" or \"postcard\". Use letter with letters, or postcard with postcard. If omitted, postcard is inferred when postcard is present.",
"type": "string"
},
"senderEmail": {
"description": "Optional order contact email. Hosted Stripe Checkout collects the payer email when omitted.",
"type": "string"
},
"stampImage": {
"description": "Letter stamp image asset ID string or upload_asset-style object. Equivalent to stampImageAssetId."
},
"stampImageAssetId": {
"description": "Asset ID returned by upload_asset for a letter-stamp-image.",
"type": "string"
},
"templateMessage": {
"description": "Shared letter template used when composeMode is template. Supports {{name}}, {{first_name}}, {{address}}, {{street}}, {{city}}, {{postal_code}}, {{country}}, and recipient customFields. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"variableKeys": {
"description": "Letter template variable keys used for recipient customFields.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"name": "quote_order",
"outputSchema": {
"additionalProperties": false,
"properties": {
"accountId": {
"type": "string"
},
"amountCents": {
"type": "number"
},
"approvalStatus": {
"enum": [
"pending",
"approved",
"rejected"
],
"type": "string"
},
"approvedForDirectSend": {
"type": "boolean"
},
"creditsEnabled": {
"type": "boolean"
},
"guidance": {
"additionalProperties": false,
"properties": {
"nextAction": {
"enum": [
"create_payment_link",
"create_checkout_link",
"create_credit_topup",
"create_direct_order"
],
"type": "string"
},
"recommendedMaxAmountCents": {
"type": "number"
},
"recommendedTopupAmountCents": {
"type": [
"number",
"null"
]
},
"requiresConfirmLiveSend": {
"type": "boolean"
},
"requiresIdempotencyKey": {
"type": "boolean"
},
"walletDirectSendAlternative": {
"additionalProperties": false,
"properties": {
"nextAction": {
"enum": [
"create_credit_topup",
"create_direct_order"
],
"type": "string"
},
"recommendedMaxAmountCents": {
"type": "number"
},
"recommendedTopupAmountCents": {
"type": [
"number",
"null"
]
},
"requiresConfirmLiveSend": {
"type": "boolean"
},
"requiresIdempotencyKey": {
"type": "boolean"
}
},
"required": [
"nextAction",
"recommendedMaxAmountCents",
"recommendedTopupAmountCents",
"requiresConfirmLiveSend",
"requiresIdempotencyKey"
],
"type": "object"
}
},
"required": [
"nextAction",
"recommendedMaxAmountCents",
"recommendedTopupAmountCents",
"requiresConfirmLiveSend",
"requiresIdempotencyKey",
"walletDirectSendAlternative"
],
"type": "object"
},
"liveEnabled": {
"type": "boolean"
},
"missingBalanceCents": {
"type": "number"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"recipientCount": {
"type": "number"
},
"requestType": {
"enum": [
"letter",
"postcard"
],
"type": "string"
},
"requiresTopup": {
"type": "boolean"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"accountId",
"amountCents",
"approvalStatus",
"approvedForDirectSend",
"creditsEnabled",
"guidance",
"liveEnabled",
"missingBalanceCents",
"mode",
"recipientCount",
"requestType",
"requiresTopup",
"wallet"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Create a hosted payment link for one-off MCP letter or postcard sending without public API keys or wallet credits. Provide exactly one of letters or postcard. Mail is sent only after checkout is paid. senderEmail is optional; Stripe Checkout collects the payer email when omitted. returnUrl is optional; PieterPost provides a hosted return page when omitted. Review the final message text before creating the link.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"composeMode": {
"description": "Letter compose mode. Allowed values: \"personal\" or \"template\". personal uses each letter.message; template uses templateMessage and recipient customFields to generate each letter.",
"type": "string"
},
"externalId": {
"description": "Your correlation id for the created order/link.",
"type": "string"
},
"idempotencyKey": {
"description": "Stable idempotency key for retries. Always include this for create operations, especially in live mode.",
"type": "string"
},
"letters": {
"description": "Bulk letters. Maximum 25.",
"items": {
"additionalProperties": false,
"description": "One letter for one recipient. In personal mode include a message, uploaded attachments, or both. In template mode, templateMessage can supply the message for every recipient. Destination page limits apply to the combined message and attachment pages.",
"properties": {
"attachments": {
"description": "Letter attachment asset IDs or upload_asset objects. Assets must be kind letter-attachment.",
"items": {
"description": "Attachment asset ID string or upload_asset-style object with assetId."
},
"type": "array"
},
"message": {
"description": "Letter body. Trimmed to 6,000 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"required": [
"recipient"
],
"type": "object"
},
"type": "array"
},
"locale": {
"description": "Locale. Allowed values: \"de\", \"en\", \"es\", \"fr\", \"it\", or \"nl\".",
"type": "string"
},
"metadata": {
"additionalProperties": true,
"description": "Up to 20 string, number, or boolean values copied to the order/link.",
"type": "object"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"postcard": {
"additionalProperties": false,
"description": "Postcard payload. Provide recipient for one card or recipients for bulk cards up to 25 recipients. Add frontImageAssetId or frontImage when you want a square 1:1 custom front instead of the default one.",
"properties": {
"composeMode": {
"description": "Compose mode. Allowed values: \"personal\" or \"template\". personal sends one message as written; template lets recipient customFields replace variables in supported templates.",
"type": "string"
},
"frontImage": {
"description": "Optional square 1:1 postcard image asset ID string or upload_asset-style object. Equivalent to frontImageAssetId."
},
"frontImageAssetId": {
"description": "Optional asset ID returned by upload_asset for a square 1:1 postcard-image.",
"type": "string"
},
"message": {
"description": "Postcard message. Trimmed to 1,200 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"recipients": {
"description": "Bulk postcard recipients. Maximum 25.",
"items": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array"
},
"variableKeys": {
"description": "Template variable keys to use for postcard personalization.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"requestType": {
"description": "Request type. Allowed values: \"letter\" or \"postcard\". Use letter with letters, or postcard with postcard. If omitted, postcard is inferred when postcard is present.",
"type": "string"
},
"senderEmail": {
"description": "Optional order contact email. Hosted Stripe Checkout collects the payer email when omitted.",
"type": "string"
},
"stampImage": {
"description": "Letter stamp image asset ID string or upload_asset-style object. Equivalent to stampImageAssetId."
},
"stampImageAssetId": {
"description": "Asset ID returned by upload_asset for a letter-stamp-image.",
"type": "string"
},
"templateMessage": {
"description": "Shared letter template used when composeMode is template. Supports {{name}}, {{first_name}}, {{address}}, {{street}}, {{city}}, {{postal_code}}, {{country}}, and recipient customFields. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"variableKeys": {
"description": "Letter template variable keys used for recipient customFields.",
"items": {
"type": "string"
},
"type": "array"
},
"paymentMethod": {
"description": "Stripe-hosted checkout payment method. Allowed values: \"auto\", \"card\", or \"ideal\". auto is the default and offers card plus iDEAL for EUR checkout. ideal is available for EUR letter and postcard checkout links and EUR wallet top-ups.",
"type": "string"
},
"returnUrl": {
"description": "Optional checkout success/cancel redirect. PieterPost appends checkout=success or checkout=cancelled. Defaults to a PieterPost-hosted MCP return page.",
"type": "string"
}
},
"type": "object"
},
"name": "create_payment_link",
"outputSchema": {
"additionalProperties": false,
"properties": {
"amountCents": {
"type": "number"
},
"billingMode": {
"enum": [
"credits",
"hosted_checkout"
],
"type": "string"
},
"checkoutUrl": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"error": {
"type": [
"string",
"null"
]
},
"expiresAt": {
"type": [
"string",
"null"
]
},
"externalId": {
"type": [
"string",
"null"
]
},
"fulfilledAt": {
"type": [
"string",
"null"
]
},
"metadata": {
"additionalProperties": true,
"type": "object"
},
"orderId": {
"type": "string"
},
"orderRef": {
"type": "string"
},
"paidAt": {
"type": [
"string",
"null"
]
},
"paymentReference": {
"type": [
"string",
"null"
]
},
"publicCheckoutUrl": {
"type": [
"string",
"null"
]
},
"recipientCount": {
"type": "number"
},
"requestType": {
"enum": [
"letter",
"postcard"
],
"type": "string"
},
"senderEmail": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"draft",
"checkout_open",
"paid",
"queued",
"fulfilled",
"failed",
"cancelled",
"expired"
],
"type": "string"
},
"testMode": {
"type": "boolean"
},
"updatedAt": {
"type": "string"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
},
"paymentLinkUrl": {
"type": [
"string",
"null"
]
}
},
"required": [
"amountCents",
"billingMode",
"checkoutUrl",
"createdAt",
"currency",
"error",
"expiresAt",
"externalId",
"fulfilledAt",
"metadata",
"orderId",
"orderRef",
"paidAt",
"paymentReference",
"publicCheckoutUrl",
"recipientCount",
"requestType",
"senderEmail",
"status",
"testMode",
"updatedAt",
"paymentLinkUrl"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Create a hosted checkout link for letters or postcards. This is the public-API-compatible name for create_payment_link. Provide exactly one of letters or postcard. Supports bulk letters, letter template mode, custom letter stamps, bulk postcard recipients up to 25 recipients, letter attachments, and optional square 1:1 custom postcard front images. Mail is sent only after checkout is paid. senderEmail is optional for MCP calls; Stripe Checkout collects the payer email when omitted. returnUrl is optional for MCP calls. Review the final message text before creating the link.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"composeMode": {
"description": "Letter compose mode. Allowed values: \"personal\" or \"template\". personal uses each letter.message; template uses templateMessage and recipient customFields to generate each letter.",
"type": "string"
},
"externalId": {
"description": "Your correlation id for the created order/link.",
"type": "string"
},
"idempotencyKey": {
"description": "Stable idempotency key for retries. Always include this for create operations, especially in live mode.",
"type": "string"
},
"letters": {
"description": "Bulk letters. Maximum 25.",
"items": {
"additionalProperties": false,
"description": "One letter for one recipient. In personal mode include a message, uploaded attachments, or both. In template mode, templateMessage can supply the message for every recipient. Destination page limits apply to the combined message and attachment pages.",
"properties": {
"attachments": {
"description": "Letter attachment asset IDs or upload_asset objects. Assets must be kind letter-attachment.",
"items": {
"description": "Attachment asset ID string or upload_asset-style object with assetId."
},
"type": "array"
},
"message": {
"description": "Letter body. Trimmed to 6,000 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"required": [
"recipient"
],
"type": "object"
},
"type": "array"
},
"locale": {
"description": "Locale. Allowed values: \"de\", \"en\", \"es\", \"fr\", \"it\", or \"nl\".",
"type": "string"
},
"metadata": {
"additionalProperties": true,
"description": "Up to 20 string, number, or boolean values copied to the order/link.",
"type": "object"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"postcard": {
"additionalProperties": false,
"description": "Postcard payload. Provide recipient for one card or recipients for bulk cards up to 25 recipients. Add frontImageAssetId or frontImage when you want a square 1:1 custom front instead of the default one.",
"properties": {
"composeMode": {
"description": "Compose mode. Allowed values: \"personal\" or \"template\". personal sends one message as written; template lets recipient customFields replace variables in supported templates.",
"type": "string"
},
"frontImage": {
"description": "Optional square 1:1 postcard image asset ID string or upload_asset-style object. Equivalent to frontImageAssetId."
},
"frontImageAssetId": {
"description": "Optional asset ID returned by upload_asset for a square 1:1 postcard-image.",
"type": "string"
},
"message": {
"description": "Postcard message. Trimmed to 1,200 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"recipients": {
"description": "Bulk postcard recipients. Maximum 25.",
"items": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array"
},
"variableKeys": {
"description": "Template variable keys to use for postcard personalization.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"requestType": {
"description": "Request type. Allowed values: \"letter\" or \"postcard\". Use letter with letters, or postcard with postcard. If omitted, postcard is inferred when postcard is present.",
"type": "string"
},
"senderEmail": {
"description": "Optional order contact email. Hosted Stripe Checkout collects the payer email when omitted.",
"type": "string"
},
"stampImage": {
"description": "Letter stamp image asset ID string or upload_asset-style object. Equivalent to stampImageAssetId."
},
"stampImageAssetId": {
"description": "Asset ID returned by upload_asset for a letter-stamp-image.",
"type": "string"
},
"templateMessage": {
"description": "Shared letter template used when composeMode is template. Supports {{name}}, {{first_name}}, {{address}}, {{street}}, {{city}}, {{postal_code}}, {{country}}, and recipient customFields. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"variableKeys": {
"description": "Letter template variable keys used for recipient customFields.",
"items": {
"type": "string"
},
"type": "array"
},
"paymentMethod": {
"description": "Stripe-hosted checkout payment method. Allowed values: \"auto\", \"card\", or \"ideal\". auto is the default and offers card plus iDEAL for EUR checkout. ideal is available for EUR letter and postcard checkout links and EUR wallet top-ups.",
"type": "string"
},
"returnUrl": {
"description": "Optional checkout success/cancel redirect. PieterPost appends checkout=success or checkout=cancelled. Defaults to a PieterPost-hosted MCP return page.",
"type": "string"
}
},
"type": "object"
},
"name": "create_checkout_link",
"outputSchema": {
"additionalProperties": false,
"properties": {
"amountCents": {
"type": "number"
},
"billingMode": {
"enum": [
"credits",
"hosted_checkout"
],
"type": "string"
},
"checkoutUrl": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"error": {
"type": [
"string",
"null"
]
},
"expiresAt": {
"type": [
"string",
"null"
]
},
"externalId": {
"type": [
"string",
"null"
]
},
"fulfilledAt": {
"type": [
"string",
"null"
]
},
"metadata": {
"additionalProperties": true,
"type": "object"
},
"orderId": {
"type": "string"
},
"orderRef": {
"type": "string"
},
"paidAt": {
"type": [
"string",
"null"
]
},
"paymentReference": {
"type": [
"string",
"null"
]
},
"publicCheckoutUrl": {
"type": [
"string",
"null"
]
},
"recipientCount": {
"type": "number"
},
"requestType": {
"enum": [
"letter",
"postcard"
],
"type": "string"
},
"senderEmail": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"draft",
"checkout_open",
"paid",
"queued",
"fulfilled",
"failed",
"cancelled",
"expired"
],
"type": "string"
},
"testMode": {
"type": "boolean"
},
"updatedAt": {
"type": "string"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"amountCents",
"billingMode",
"checkoutUrl",
"createdAt",
"currency",
"error",
"expiresAt",
"externalId",
"fulfilledAt",
"metadata",
"orderId",
"orderRef",
"paidAt",
"paymentReference",
"publicCheckoutUrl",
"recipientCount",
"requestType",
"senderEmail",
"status",
"testMode",
"updatedAt"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": true,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Create a direct-send order paid from wallet credits. Provide exactly one of letters or postcard. Supports bulk letters and postcards with the same payload shape as hosted checkout. Test mode simulates sending. Live mode sends real mail and requires confirmLiveSend=true plus maxAmountCents >= the calculated total. Review the final message text before sending.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"composeMode": {
"description": "Letter compose mode. Allowed values: \"personal\" or \"template\". personal uses each letter.message; template uses templateMessage and recipient customFields to generate each letter.",
"type": "string"
},
"externalId": {
"description": "Your correlation id for the created order/link.",
"type": "string"
},
"idempotencyKey": {
"description": "Stable idempotency key for retries. Always include this for create operations, especially in live mode.",
"type": "string"
},
"letters": {
"description": "Bulk letters. Maximum 25.",
"items": {
"additionalProperties": false,
"description": "One letter for one recipient. In personal mode include a message, uploaded attachments, or both. In template mode, templateMessage can supply the message for every recipient. Destination page limits apply to the combined message and attachment pages.",
"properties": {
"attachments": {
"description": "Letter attachment asset IDs or upload_asset objects. Assets must be kind letter-attachment.",
"items": {
"description": "Attachment asset ID string or upload_asset-style object with assetId."
},
"type": "array"
},
"message": {
"description": "Letter body. Trimmed to 6,000 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
}
},
"required": [
"recipient"
],
"type": "object"
},
"type": "array"
},
"locale": {
"description": "Locale. Allowed values: \"de\", \"en\", \"es\", \"fr\", \"it\", or \"nl\".",
"type": "string"
},
"metadata": {
"additionalProperties": true,
"description": "Up to 20 string, number, or boolean values copied to the order/link.",
"type": "object"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"postcard": {
"additionalProperties": false,
"description": "Postcard payload. Provide recipient for one card or recipients for bulk cards up to 25 recipients. Add frontImageAssetId or frontImage when you want a square 1:1 custom front instead of the default one.",
"properties": {
"composeMode": {
"description": "Compose mode. Allowed values: \"personal\" or \"template\". personal sends one message as written; template lets recipient customFields replace variables in supported templates.",
"type": "string"
},
"frontImage": {
"description": "Optional square 1:1 postcard image asset ID string or upload_asset-style object. Equivalent to frontImageAssetId."
},
"frontImageAssetId": {
"description": "Optional asset ID returned by upload_asset for a square 1:1 postcard-image.",
"type": "string"
},
"message": {
"description": "Postcard message. Trimmed to 1,200 characters. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"recipient": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"recipients": {
"description": "Bulk postcard recipients. Maximum 25.",
"items": {
"additionalProperties": true,
"description": "Recipient address. Provide name plus addressLines, or name with streetAddress or street plus number, postalCode, city, country, and state when required. Free-form address parsing is not performed.",
"properties": {
"addressLines": {
"description": "Preformatted address lines, excluding the recipient name.",
"items": {
"type": "string"
},
"type": "array"
},
"city": {
"type": "string"
},
"country": {
"type": "string"
},
"customFields": {
"description": "Template variables available when letter or postcard composeMode is template.",
"additionalProperties": {
"type": "string"
},
"type": "object"
},
"extra": {
"type": "string"
},
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"number": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"state": {
"type": "string"
},
"street": {
"type": "string"
},
"streetAddress": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"type": "array"
},
"variableKeys": {
"description": "Template variable keys to use for postcard personalization.",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
},
"requestType": {
"description": "Request type. Allowed values: \"letter\" or \"postcard\". Use letter with letters, or postcard with postcard. If omitted, postcard is inferred when postcard is present.",
"type": "string"
},
"senderEmail": {
"description": "Optional order contact email. Hosted Stripe Checkout collects the payer email when omitted.",
"type": "string"
},
"stampImage": {
"description": "Letter stamp image asset ID string or upload_asset-style object. Equivalent to stampImageAssetId."
},
"stampImageAssetId": {
"description": "Asset ID returned by upload_asset for a letter-stamp-image.",
"type": "string"
},
"templateMessage": {
"description": "Shared letter template used when composeMode is template. Supports {{name}}, {{first_name}}, {{address}}, {{street}}, {{city}}, {{postal_code}}, {{country}}, and recipient customFields. Use \\n for line breaks; line breaks are preserved.",
"type": "string"
},
"variableKeys": {
"description": "Letter template variable keys used for recipient customFields.",
"items": {
"type": "string"
},
"type": "array"
},
"confirmLiveSend": {
"description": "Required true for live mode after explicit user confirmation.",
"type": "boolean"
},
"maxAmountCents": {
"description": "Required for live mode; caps the total spend.",
"type": "number"
}
},
"type": "object"
},
"name": "create_direct_order",
"outputSchema": {
"additionalProperties": false,
"properties": {
"amountCents": {
"type": "number"
},
"billingMode": {
"enum": [
"credits",
"hosted_checkout"
],
"type": "string"
},
"checkoutUrl": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"error": {
"type": [
"string",
"null"
]
},
"expiresAt": {
"type": [
"string",
"null"
]
},
"externalId": {
"type": [
"string",
"null"
]
},
"fulfilledAt": {
"type": [
"string",
"null"
]
},
"metadata": {
"additionalProperties": true,
"type": "object"
},
"orderId": {
"type": "string"
},
"orderRef": {
"type": "string"
},
"paidAt": {
"type": [
"string",
"null"
]
},
"paymentReference": {
"type": [
"string",
"null"
]
},
"publicCheckoutUrl": {
"type": [
"string",
"null"
]
},
"recipientCount": {
"type": "number"
},
"requestType": {
"enum": [
"letter",
"postcard"
],
"type": "string"
},
"senderEmail": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"draft",
"checkout_open",
"paid",
"queued",
"fulfilled",
"failed",
"cancelled",
"expired"
],
"type": "string"
},
"testMode": {
"type": "boolean"
},
"updatedAt": {
"type": "string"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"amountCents",
"billingMode",
"checkoutUrl",
"createdAt",
"currency",
"error",
"expiresAt",
"externalId",
"fulfilledAt",
"metadata",
"orderId",
"orderRef",
"paidAt",
"paymentReference",
"publicCheckoutUrl",
"recipientCount",
"requestType",
"senderEmail",
"status",
"testMode",
"updatedAt"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Upload a square 1:1 postcard front image, letter attachment, or custom letter stamp for later use in create_checkout_link or create_direct_order. Provide exactly one of fileBase64 or a public HTTPS fileUrl. Returns an assetId that can be passed as postcard.frontImageAssetId, stampImageAssetId, or in a letter attachments array.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"contentType": {
"description": "Content type. Common values: \"application/pdf\" for letter attachments, or \"image/png\" / \"image/jpeg\" for images.",
"type": "string"
},
"fileBase64": {
"description": "Base64-encoded file contents.",
"type": "string"
},
"fileName": {
"description": "Original file name, used for extension validation.",
"type": "string"
},
"fileUrl": {
"description": "Public HTTPS URL to fetch. Private and localhost URLs are rejected.",
"type": "string"
},
"kind": {
"description": "Upload kind. Allowed values: \"letter-attachment\", \"letter-stamp-image\", or \"postcard-image\".",
"type": "string"
}
},
"required": [
"kind",
"fileName",
"contentType"
],
"type": "object"
},
"name": "upload_asset",
"outputSchema": {
"additionalProperties": true,
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "Read the API wallet balance and account capability flags for test or live mode.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"currency": {
"description": "Currency. Allowed values: \"eur\" or \"usd\".",
"type": "string"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
}
},
"type": "object"
},
"name": "get_wallet",
"outputSchema": {
"additionalProperties": false,
"properties": {
"accountId": {
"type": "string"
},
"approvalStatus": {
"enum": [
"pending",
"approved",
"rejected"
],
"type": "string"
},
"approvedForDirectSend": {
"type": "boolean"
},
"creditsEnabled": {
"type": "boolean"
},
"hostedApiEnabled": {
"type": "boolean"
},
"liveEnabled": {
"type": "boolean"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"accountId",
"approvalStatus",
"approvedForDirectSend",
"creditsEnabled",
"hostedApiEnabled",
"liveEnabled",
"wallet"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "Fetch a PieterPost API order by id, including hosted checkout/direct-send status, recipient count, amount, and error details.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"orderId": {
"type": "string"
}
},
"required": [
"orderId"
],
"type": "object"
},
"name": "get_order",
"outputSchema": {
"additionalProperties": false,
"properties": {
"amountCents": {
"type": "number"
},
"billingMode": {
"enum": [
"credits",
"hosted_checkout"
],
"type": "string"
},
"checkoutUrl": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"error": {
"type": [
"string",
"null"
]
},
"expiresAt": {
"type": [
"string",
"null"
]
},
"externalId": {
"type": [
"string",
"null"
]
},
"fulfilledAt": {
"type": [
"string",
"null"
]
},
"metadata": {
"additionalProperties": true,
"type": "object"
},
"orderId": {
"type": "string"
},
"orderRef": {
"type": "string"
},
"paidAt": {
"type": [
"string",
"null"
]
},
"paymentReference": {
"type": [
"string",
"null"
]
},
"publicCheckoutUrl": {
"type": [
"string",
"null"
]
},
"recipientCount": {
"type": "number"
},
"requestType": {
"enum": [
"letter",
"postcard"
],
"type": "string"
},
"senderEmail": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"draft",
"checkout_open",
"paid",
"queued",
"fulfilled",
"failed",
"cancelled",
"expired"
],
"type": "string"
},
"testMode": {
"type": "boolean"
},
"updatedAt": {
"type": "string"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"amountCents",
"billingMode",
"checkoutUrl",
"createdAt",
"currency",
"error",
"expiresAt",
"externalId",
"fulfilledAt",
"metadata",
"orderId",
"orderRef",
"paidAt",
"paymentReference",
"publicCheckoutUrl",
"recipientCount",
"requestType",
"senderEmail",
"status",
"testMode",
"updatedAt"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "Fetch a PieterPost wallet top-up by id, including payment status and checkout URL when still pending.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"topupId": {
"type": "string"
}
},
"required": [
"topupId"
],
"type": "object"
},
"name": "get_topup",
"outputSchema": {
"additionalProperties": false,
"properties": {
"amountCents": {
"type": "number"
},
"checkoutUrl": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"paidAt": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"pending",
"paid",
"cancelled",
"expired",
"failed"
],
"type": "string"
},
"testMode": {
"type": "boolean"
},
"topupId": {
"type": "string"
},
"updatedAt": {
"type": "string"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"amountCents",
"checkoutUrl",
"createdAt",
"currency",
"paidAt",
"status",
"testMode",
"topupId",
"updatedAt"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "List recent PieterPost wallet top-ups for this account. Use mode and currency filters to inspect the active live or test funding history.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"currency": {
"description": "Currency. Allowed values: \"eur\" or \"usd\".",
"type": "string"
},
"limit": {
"description": "Maximum number of top-ups to return. Typical range is 1 to 20.",
"type": "number"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
}
},
"type": "object"
},
"name": "list_topups",
"outputSchema": {
"additionalProperties": false,
"properties": {
"topups": {
"items": {
"additionalProperties": false,
"properties": {
"amountCents": {
"type": "number"
},
"checkoutUrl": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"paidAt": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"pending",
"paid",
"cancelled",
"expired",
"failed"
],
"type": "string"
},
"testMode": {
"type": "boolean"
},
"topupId": {
"type": "string"
},
"updatedAt": {
"type": "string"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"amountCents",
"checkoutUrl",
"createdAt",
"currency",
"paidAt",
"status",
"testMode",
"topupId",
"updatedAt"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"topups"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Create a test credit top-up immediately, or create a live Stripe checkout URL for adding API credits used by direct-send orders. paymentMethod=auto is the default; for EUR top-ups it offers both card and iDEAL. Pass paymentMethod=card or paymentMethod=ideal only when the user wants to force one method.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"amountCents": {
"description": "Top-up amount in cents. Rounded up to whole euros.",
"type": "number"
},
"currency": {
"description": "Currency. Allowed values: \"eur\" or \"usd\".",
"type": "string"
},
"idempotencyKey": {
"description": "Stable idempotency key for retries. Always include this for create operations, especially in live mode.",
"type": "string"
},
"metadata": {
"additionalProperties": true,
"description": "Up to 20 string, number, or boolean values copied to the order/link.",
"type": "object"
},
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"paymentMethod": {
"description": "Stripe-hosted checkout payment method. Allowed values: \"auto\", \"card\", or \"ideal\". auto is the default and offers card plus iDEAL for EUR checkout. ideal is available for EUR letter and postcard checkout links and EUR wallet top-ups.",
"type": "string"
},
"returnUrl": {
"description": "Used for live Stripe checkout success/cancel redirects.",
"type": "string"
}
},
"required": [
"amountCents"
],
"type": "object"
},
"name": "create_credit_topup",
"outputSchema": {
"additionalProperties": false,
"properties": {
"amountCents": {
"type": "number"
},
"checkoutUrl": {
"type": [
"string",
"null"
]
},
"createdAt": {
"type": "string"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"paidAt": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"pending",
"paid",
"cancelled",
"expired",
"failed"
],
"type": "string"
},
"testMode": {
"type": "boolean"
},
"topupId": {
"type": "string"
},
"updatedAt": {
"type": "string"
},
"wallet": {
"additionalProperties": false,
"properties": {
"balanceCents": {
"type": "number"
},
"currency": {
"enum": [
"eur",
"usd"
],
"type": "string"
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"updatedAt": {
"type": "string"
}
},
"required": [
"balanceCents",
"currency",
"mode",
"updatedAt"
],
"type": "object"
}
},
"required": [
"amountCents",
"checkoutUrl",
"createdAt",
"currency",
"paidAt",
"status",
"testMode",
"topupId",
"updatedAt"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": false,
"readOnlyHint": true
},
"description": "List API key metadata for this PieterPost API account. Secrets are never returned.",
"inputSchema": {
"additionalProperties": false,
"properties": {},
"type": "object"
},
"name": "list_api_keys",
"outputSchema": {
"additionalProperties": false,
"properties": {
"keys": {
"items": {
"additionalProperties": false,
"properties": {
"createdAt": {
"type": "string"
},
"id": {
"type": "string"
},
"lastUsedAt": {
"type": [
"string",
"null"
]
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"name": {
"type": "string"
},
"revokedAt": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"active",
"paused",
"revoked"
],
"type": "string"
},
"tokenLast4": {
"type": "string"
}
},
"required": [
"createdAt",
"id",
"lastUsedAt",
"mode",
"name",
"revokedAt",
"status",
"tokenLast4"
],
"type": "object"
},
"type": "array"
}
},
"required": [
"keys"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": false,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Create a new PieterPost public API key. The secret is returned once and cannot be recovered later.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"mode": {
"description": "Mode. Allowed values: \"test\" or \"live\". Defaults to test when omitted.",
"type": "string"
},
"name": {
"description": "Human-readable key name.",
"type": "string"
}
},
"type": "object"
},
"name": "create_api_key",
"outputSchema": {
"additionalProperties": false,
"properties": {
"key": {
"additionalProperties": false,
"properties": {
"createdAt": {
"type": "string"
},
"id": {
"type": "string"
},
"lastUsedAt": {
"type": [
"string",
"null"
]
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"name": {
"type": "string"
},
"revokedAt": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"active",
"paused",
"revoked"
],
"type": "string"
},
"tokenLast4": {
"type": "string"
}
},
"required": [
"createdAt",
"id",
"lastUsedAt",
"mode",
"name",
"revokedAt",
"status",
"tokenLast4"
],
"type": "object"
},
"secret": {
"type": "string"
},
"warning": {
"type": "string"
}
},
"required": [
"key",
"secret",
"warning"
],
"type": "object"
}
},
{
"annotations": {
"destructiveHint": true,
"openWorldHint": true,
"readOnlyHint": false
},
"description": "Revoke an existing PieterPost public API key by id.",
"inputSchema": {
"additionalProperties": false,
"properties": {
"keyId": {
"type": "string"
}
},
"required": [
"keyId"
],
"type": "object"
},
"name": "revoke_api_key",
"outputSchema": {
"additionalProperties": false,
"properties": {
"key": {
"additionalProperties": false,
"properties": {
"createdAt": {
"type": "string"
},
"id": {
"type": "string"
},
"lastUsedAt": {
"type": [
"string",
"null"
]
},
"mode": {
"enum": [
"test",
"live"
],
"type": "string"
},
"name": {
"type": "string"
},
"revokedAt": {
"type": [
"string",
"null"
]
},
"status": {
"enum": [
"active",
"paused",
"revoked"
],
"type": "string"
},
"tokenLast4": {
"type": "string"
}
},
"required": [
"createdAt",
"id",
"lastUsedAt",
"mode",
"name",
"revokedAt",
"status",
"tokenLast4"
],
"type": "object"
},
"revoked": {
"type": "boolean"
}
},
"required": [
"key",
"revoked"
],
"type": "object"
}
}
]
}
Example tool arguments
list_mailbook_contacts before sending to a saved contact
{
"limit": 5,
"query": "Bart"
}
quote_order for a postcard to a Mailbook contact
{
"idempotencyKey": "postcard_bart_2026_05_01_quote",
"mode": "live",
"postcard": {
"message": "Hi Bart,\nA postcard from PieterPost MCP.",
"recipient": {
"addressLines": [
"Keizersgracht 1",
"1012 AB Amsterdam",
"Netherlands"
],
"city": "Amsterdam",
"country": "NL",
"id": "contact_bart_123",
"name": "Bart",
"postalCode": "1012 AB",
"streetAddress": "Keizersgracht 1"
}
},
"requestType": "postcard"
}
upload_asset for a postcard image
{
"contentType": "image/jpeg",
"fileName": "front.jpg",
"fileUrl": "https://example.com/front.jpg",
"kind": "postcard-image"
}
quote_order before a live direct-send postcard
{
"idempotencyKey": "quote_live_postcard_123",
"locale": "en",
"mode": "live",
"postcard": {
"frontImageAssetId": "asset_postcard_front_123",
"message": "Bart,\nA postcard from PieterPost MCP.",
"recipient": {
"city": "Amsterdam",
"country": "NL",
"customFields": {
"gift_code": "SPRING-10"
},
"name": "Pieter Example",
"postalCode": "1012 AB",
"streetAddress": "Damrak 1"
}
},
"requestType": "postcard"
}
upload_asset for a letter attachment
{
"contentType": "application/pdf",
"fileBase64": "JVBERi0xLjQK...",
"fileName": "receipt.pdf",
"kind": "letter-attachment"
}
upload_asset for a letter stamp image
{
"contentType": "image/png",
"fileBase64": "iVBORw0KGgo...",
"fileName": "stamp.png",
"kind": "letter-stamp-image"
}
create_payment_link for a letter with attachment
{
"externalId": "invoice_123",
"idempotencyKey": "invoice_123_checkout",
"letters": [
{
"attachments": [
"asset_letter_pdf_123"
],
"message": "Thanks for your order. The receipt PDF is enclosed.",
"recipient": {
"city": "Amsterdam",
"country": "NL",
"customFields": {
"gift_code": "SPRING-10"
},
"name": "Pieter Example",
"postalCode": "1012 AB",
"streetAddress": "Damrak 1"
}
}
],
"locale": "en",
"metadata": {
"customerId": "cus_123"
},
"mode": "test",
"requestType": "letter"
}
create_payment_link for bulk template letters
{
"composeMode": "template",
"externalId": "spring_campaign_123",
"idempotencyKey": "spring_campaign_123_checkout",
"letters": [
{
"recipient": {
"city": "Amsterdam",
"country": "NL",
"customFields": {
"gift_code": "SPRING-10"
},
"name": "Pieter Example",
"postalCode": "1012 AB",
"streetAddress": "Damrak 1"
}
},
{
"recipient": {
"city": "Amsterdam",
"country": "NL",
"customFields": {
"gift_code": "SPRING-20"
},
"name": "Sam Example",
"postalCode": "1012 AB",
"streetAddress": "Damrak 1"
}
}
],
"locale": "en",
"mode": "test",
"requestType": "letter",
"stampImageAssetId": "asset_stamp_123",
"templateMessage": "Hi {{first_name}},\nYour spring code is {{gift_code}}.",
"variableKeys": [
"gift_code"
]
}
create_payment_link for a postcard
{
"idempotencyKey": "postcard_123_checkout",
"locale": "en",
"mode": "test",
"paymentMethod": "ideal",
"postcard": {
"frontImageAssetId": "asset_postcard_front_123",
"message": "A small card from PieterPost.",
"recipients": [
{
"city": "Amsterdam",
"country": "NL",
"customFields": {
"gift_code": "SPRING-10"
},
"name": "Pieter Example",
"postalCode": "1012 AB",
"streetAddress": "Damrak 1"
}
]
},
"requestType": "postcard"
}
create_direct_order for live wallet-funded mail
{
"composeMode": "template",
"externalId": "spring_campaign_123",
"idempotencyKey": "spring_campaign_123_live_send",
"letters": [
{
"recipient": {
"city": "Amsterdam",
"country": "NL",
"customFields": {
"gift_code": "SPRING-10"
},
"name": "Pieter Example",
"postalCode": "1012 AB",
"streetAddress": "Damrak 1"
}
},
{
"recipient": {
"city": "Amsterdam",
"country": "NL",
"customFields": {
"gift_code": "SPRING-20"
},
"name": "Sam Example",
"postalCode": "1012 AB",
"streetAddress": "Damrak 1"
}
}
],
"locale": "en",
"mode": "live",
"requestType": "letter",
"stampImageAssetId": "asset_stamp_123",
"templateMessage": "Hi {{first_name}},\nYour spring code is {{gift_code}}.",
"variableKeys": [
"gift_code"
],
"confirmLiveSend": true,
"maxAmountCents": 2000
}
create_credit_topup
{
"amountCents": 2500,
"currency": "eur",
"idempotencyKey": "credits_2026_04",
"metadata": {
"source": "mcp"
},
"mode": "live",
"paymentMethod": "ideal",
"returnUrl": "https://example.com/topups/return"
}
get_topup
{
"mode": "live",
"topupId": "topup_123"
}
list_topups
{
"currency": "eur",
"limit": 5,
"mode": "live"
}
Operational guidance for agents
- Start with
searchorfetchwhen the user asks how PieterPost works or you need account context. - When the user refers to a saved contact by name, call
list_mailbook_contactsand confirm the selected recipient if the search returns ambiguous matches. - For requests like
send this message to Bart, do not ask for Bart's address first. Search Mailbook for Bart, use the selectedrecipient, then review the final message and continue through the normal quote/send flow. - Use
quote_orderbefore the first live letter or postcard so you can confirm the amount, recipient count, and next action. - For ordinary requests like
send a letter to ..., default to one-off sending withcreate_payment_link, not wallet credits or public API keys. - Before any send or hosted checkout handoff, read back and verify the final message text you are placing on the letter or postcard.
- Use
upload_assetbefore any order requiring postcard fronts, letter attachments, or custom letter stamps. For postcards, only use square 1:1 custom front images. - Prefer
create_payment_linkwhen a payer should review and pay in hosted checkout without API keys or wallet credits.create_checkout_linkremains available as the API-compatible alias. - Prefer
create_compose_linkwhen the user should review or edit a single recipient message in PieterPost. - Use
get_topuporlist_topupsto confirm whether a live wallet top-up is still pending or already paid. - Use
create_direct_orderwhen the user wants wallet-funded/API-credit sending. For live sends, get explicit confirmation and a maximum spend cap first. - Use
idempotencyKeyfor every create operation that may be retried.