API documentation
No Errands gives an agent eight real-world abilities in the United States: print and mail letters and postcards, send faxes, book appointments with local businesses, ask a restaurant for a table by telephone, buy shipping labels, print and post photos, mail greeting cards, and get a PDF signed electronically. This page is the human version of the eight connector briefs that agents read. All of them describe the same v0 contracts.
If you only want to use this from Muse, you do not need this page. Start at Get your key instead.
The eight connectors
| Connector | Brief | MCP endpoint | REST base |
|---|---|---|---|
| No Errands Mail | /connectors/muse.md | https://api.noerrands.com/c/mail/mcp |
https://api.noerrands.com/c/mail/v1 |
| No Errands Fax | /connectors/fax/muse.md | https://api.noerrands.com/c/fax/mcp |
https://api.noerrands.com/c/fax/v1 |
| No Errands Bookings | /connectors/booking/muse.md | https://api.noerrands.com/c/booking/mcp |
https://api.noerrands.com/c/booking/v1 |
| No Errands Tables | /connectors/tables/muse.md | https://api.noerrands.com/c/tables/mcp |
https://api.noerrands.com/c/tables/v1 |
| No Errands Ship | /connectors/ship/muse.md | https://api.noerrands.com/c/ship/mcp |
https://api.noerrands.com/c/ship/v1 |
| No Errands Prints | /connectors/prints/muse.md | https://api.noerrands.com/c/prints/mcp |
https://api.noerrands.com/c/prints/v1 |
| No Errands Cards | /connectors/cards/muse.md | https://api.noerrands.com/c/cards/mcp |
https://api.noerrands.com/c/cards/v1 |
| No Errands Sign | /connectors/sign/muse.md | https://api.noerrands.com/c/sign/mcp |
https://api.noerrands.com/c/sign/v1 |
They share one account, one API key, one credit balance, one error envelope and one authentication scheme. REST and MCP take the same request bodies and return the same response bodies, so pick whichever your client speaks.
| Item | Value |
|---|---|
| OpenAPI 3.1 documents | https://api.noerrands.com/c/mail/openapi.json, https://api.noerrands.com/c/fax/openapi.json, https://api.noerrands.com/c/booking/openapi.json, https://api.noerrands.com/c/tables/openapi.json, https://api.noerrands.com/c/ship/openapi.json, https://api.noerrands.com/c/prints/openapi.json, https://api.noerrands.com/c/cards/openapi.json, https://api.noerrands.com/c/sign/openapi.json |
| Protected resource metadata (RFC 9728) | https://api.noerrands.com/.well-known/oauth-protected-resource/c/mail/mcp, https://api.noerrands.com/.well-known/oauth-protected-resource/c/fax/mcp, https://api.noerrands.com/.well-known/oauth-protected-resource/c/booking/mcp, https://api.noerrands.com/.well-known/oauth-protected-resource/c/tables/mcp, https://api.noerrands.com/.well-known/oauth-protected-resource/c/ship/mcp, https://api.noerrands.com/.well-known/oauth-protected-resource/c/prints/mcp, https://api.noerrands.com/.well-known/oauth-protected-resource/c/cards/mcp, https://api.noerrands.com/.well-known/oauth-protected-resource/c/sign/mcp |
| Health check | https://api.noerrands.com/health |
| Agent index | https://noerrands.com/llms.txt |
Authentication
Every call carries your key as a bearer token:
Authorization: Bearer ne_live_your_key_here
Keys look like ne_live_ or ne_test_ followed by 32
characters. We store only a SHA-256 hash and the first 12 characters, so we
cannot tell you your key if you lose it. Create a new one instead.
A key has one of two scopes:
| Scope | Can do |
|---|---|
read |
Check addresses, estimate cost, read status, list mail and faxes, read balance, create top-up links, search providers, read availability |
read,write |
Everything above, plus send letters, postcards and faxes, create and cancel bookings, ask for tables, buy and void shipping labels, order prints, send and cancel greeting cards, and create, send, void and delete signature envelopes |
If the key is missing or wrong you get 401 plus a
WWW-Authenticate: Bearer resource_metadata="..." header pointing at that
connector's RFC 9728 document.
Getting a key
POST https://api.noerrands.com/v1/keys - no authentication, limited to 5 requests per hour per IP.
Request: { "email": "you@example.com", "scope": "read,write" }
Response 201:
{
"account_id": "acc_...",
"api_key": "ne_live_...",
"scope": "read,write",
"balance_cents": 0,
"topup_url": "https://..."
}
The key page calls this endpoint for you. One key works for all eight connectors. Email addresses are not verified in v0; treat the key, not the email, as the account identity.
Tool classification
Every tool is classified under Meta's Muse connector guidelines (sections 3.2, 5.4 and 5.6):
- Read changes nothing anyone can observe. Safe to call without asking.
- Write changes stored state or moves credit back to the person, but buys nothing and contacts no one. A tool that reads and also writes is a Write: the status lookups that settle a refund on the ledger are Writes, and so is
create_topup_link, which creates a Stripe Checkout session but charges nothing until the person pays on Stripe's page. - Sensitive write is irreversible or consequential: a charge, a send, a booking, a dispatched driver, a cancellation or a deletion. It needs the person's explicit approval of what the connector brief lists for that tool.
| Connector | Read | Write | Sensitive write |
|---|---|---|---|
verify_address, estimate_cost, list_sent_mail, get_balance |
get_mail_status, create_topup_link |
send_letter, send_postcard, delete_my_data |
|
| Fax | estimate_fax_cost, list_faxes, get_balance |
get_fax_status, create_topup_link |
send_fax, delete_my_data |
| Bookings | search_providers, list_services, get_availability, get_booking, list_my_bookings |
none | create_booking, cancel_booking, delete_my_data |
| Restaurant tables | get_table_request, list_table_requests, get_balance |
create_topup_link |
request_table, cancel_table_request, delete_my_data |
| Shipping labels | get_shipping_rates, list_shipments, track_package, get_pickup_options, get_balance |
get_shipment, create_topup_link |
buy_label, create_return_label, void_label, schedule_pickup, cancel_pickup, delete_my_data |
| Signatures | get_envelope, list_envelopes, get_balance |
create_envelope, remind_signer, get_signed_document, create_topup_link |
send_envelope, void_envelope, delete_envelope, delete_my_data |
| Photo prints | list_print_products, quote_prints, list_print_orders, get_balance |
upload_print_image, get_print_order, create_topup_link |
order_prints, cancel_print_order, delete_my_data |
| Greeting cards | list_card_designs, list_handwriting_styles, preview_card, list_cards, get_balance |
get_card, create_topup_link |
send_card, cancel_card, delete_my_data |
Each connector brief has the full table per tool: class, side effects, cost, approval, key scope, REST route and per-tool rate limits. The same facts are in every OpenAPI operation as x-muse-classification, and the MCP annotations agree: readOnlyHint is true only on a Read, and destructiveHint is true on every Sensitive write and on nothing else, so clients that always prompt for destructive tools ask before each one. Key scope is separate from class: a read key can call every Read and the Writes that only create a checkout link or settle a refund; everything else needs read,write.
Errors
Every error has the same envelope, whichever connector produced it:
{ "error": { "code": "invalid_request", "message": "..." } }
| HTTP | code |
Extra fields | Meaning |
|---|---|---|---|
| 400 | invalid_request |
field when known |
Something in the request is wrong |
| 401 | unauthorized |
Key missing, unknown, or revoked | |
| 402 | insufficient_credits |
required_cents, balance_cents, topup_url, packs |
Not enough credits; nothing was sent |
| 403 | forbidden_scope |
A write call with a read-only key | |
| 404 | not_found |
No such record on this account | |
| 409 | idempotency_conflict |
Same idempotency_key, different body |
|
| 429 | rate_limited |
retry_after_seconds |
Slow down |
| 502 | provider_error |
An upstream provider failed; any charge was refunded |
Credits
One prepaid balance in integer cents covers mail, fax, confirmed restaurant tables, shipping labels, photo prints, greeting cards, and signature envelopes. Bookings are free and never touch it.
Buy a single letter on its own, or a pack. Every pack credits more than it costs, and the bonus is ordinary credit.
| Buy | You pay | Credits you get |
|---|---|---|
| One letter | $2.49 | $2.49, no bonus |
| $10.00 pack | $10.00 | $12.50, one free letter |
| $25.00 pack | $25.00 | $32.50, three free letters |
| $50.00 pack | $50.00 | $67.50, seven free letters |
The free letters are the bonus divided by the $2.49 first-page
letter price; spend it on postcards or faxes if you prefer. get_balance and
create_topup_link both return this table as packs, and so does the
insufficient_credits body, each entry
{ "label", "pay_cents", "credits_cents", "free_letters" }. Paying an amount
that is not on the list credits exactly what was paid.
Idempotency
Put an idempotency_key (a string up to 128 characters) on every send and every
booking. For 24 hours, a repeat of the same key with the same body returns the
original response instead of acting again. The same key with a different body
returns 409 idempotency_conflict. Use one key per human request, not per
retry.
Types
type Address = {
name: string; // 1..40 chars, required for send, optional for verify
company?: string; // <= 40
line1: string; // <= 64
line2?: string; // <= 64
city: string;
state: string; // 2-letter
zip: string; // 5 or 9 digits
country?: "US"; // US only in v0
};
type MailStatus = "created" | "processing" | "in_transit" | "delivered" | "returned" | "failed" | "cancelled";
type MailRecord = {
mail_id: string; // "ml_<id>"
kind: "letter" | "postcard";
status: MailStatus;
to: Address;
from: Address;
created_at: string; // ISO 8601
expected_delivery_date?: string; // YYYY-MM-DD
credits_charged_cents: number;
tracking_url?: string;
};
Endpoints
| MCP tool | Scope | Cost | REST |
|---|---|---|---|
verify_address |
read | free | POST /c/mail/v1/addresses/verify |
estimate_cost |
read | free | POST /c/mail/v1/estimate |
send_letter |
write | charged | POST /c/mail/v1/letters |
send_postcard |
write | charged | POST /c/mail/v1/postcards |
get_mail_status |
read | free | GET /c/mail/v1/mail/{mail_id} |
list_sent_mail |
read | free | GET /c/mail/v1/mail?limit=&cursor= |
get_balance |
read | free | GET /c/mail/v1/balance |
create_topup_link |
read | free | POST /c/mail/v1/topups |
| no tool | read | free | GET /c/mail/v1/me |
- verify_address - in
{ "address": Address }(nameoptional), out{ "deliverable": boolean, "normalized": Address, "notes": string[] }. Use thenormalizedaddress when you send. - estimate_cost - in
{ "kind": "letter" | "postcard", "pages"?: number, "color"?: boolean, "certified"?: boolean }, out{ "total_cents": number, "breakdown": [{ "item": string, "cents": number }] }. - send_letter - in
to,from, optionalsubject(<= 120 chars), exactly one ofbody_markdown,body_htmlorpdf_url(<= 20 KB), pluscolor,double_sided,certifiedandidempotency_key. Out: aMailRecordplusbalance_cents. Markdown is rendered to simple HTML; HTML is sanitized, so scripts are stripped and images load by URL. - send_postcard - in
to,from,front(textand/orimage_url),message(<= 350 characters),idempotency_key. Out: same shape assend_letter. - get_mail_status - in
{ "mail_id" }, out aMailRecordplus{ "events": [{ "at": string, "status": MailStatus, "detail"?: string }] }. - list_sent_mail - in
{ "limit"?: 1..50, "cursor"?: string }(default 20), out{ "items": MailRecord[], "next_cursor"?: string }. - get_balance - out
{ "balance_cents": number, "currency": "usd", "topup_url": string, "packs": CreditPack[] }. - create_topup_link - in
{ "amount_cents": 249 | 1000 | 2500 | 5000 }(one of those, cheapest first is the one-off single letter), out{ "checkout_url": string, "expires_at": string, "packs": CreditPack[] }. ACreditPackis{ "label", "pay_cents", "credits_cents", "free_letters" }; see Credits. - GET /me - out
{ "account_id", "email", "scope", "key_prefix", "balance_cents" }.
The server validates, estimates, checks your balance, charges, then calls the
print provider. If the provider fails after the charge, the credits are
refunded and you get 502 provider_error.
| Item | Price |
|---|---|
| Letter, first page, black and white | $2.49 |
| Each additional page | $0.30 |
| Color surcharge, per letter | $0.50 |
| Certified mail surcharge | $9.50 |
| Heavy letter postage, more than 6 sheets (6 pages single-sided, 12 double-sided) | $6.99 |
| Postcard | $1.69 |
| Address check | Free |
| Cost estimate | Free |
Fax
Types
type FaxStatus = "queued" | "sending" | "delivered" | "failed";
Endpoints
| MCP tool | Scope | Cost | REST |
|---|---|---|---|
estimate_fax_cost |
read | free | POST /c/fax/v1/estimate |
send_fax |
write | charged | POST /c/fax/v1/faxes |
get_fax_status |
read | free | GET /c/fax/v1/faxes/{fax_id} |
list_faxes |
read | free | GET /c/fax/v1/faxes?limit=&cursor= |
get_balance |
read | free | GET /c/fax/v1/balance |
create_topup_link |
read | free | POST /c/fax/v1/topups |
- estimate_fax_cost - in
{ "pages": 1..50 }, out{ "total_cents", "breakdown" }. - send_fax - in
to_number(E.164, US or CA), optionalrecipient_name, exactly one ofpdf_urlorbody_markdown, optionalcover_note(<= 500 characters) andidempotency_key. Out{ "fax_id", "status", "pages_estimated", "credits_charged_cents", "balance_cents", "to_number" }. - get_fax_status - out a fax record plus
events[]. A fax that ends infailedis refunded once. - list_faxes, get_balance, create_topup_link - as in mail. The balance and top-up endpoints read and write the same ledger.
If you supply body_markdown and the configured provider will not accept
rendered HTML, the server returns 400 invalid_request with
field: "body_markdown" and a message telling you to supply a pdf_url.
Page counts come from the provider when available. Otherwise the server estimates one page per 3,000 characters and trues up the charge when the provider reports the final count, recording the adjustment on the ledger.
| Item | Price |
|---|---|
| Fax, first page | $1.49 |
| Each additional fax page | $0.49 |
| Fax cost estimate | Free |
Restaurant tables
For restaurants that have no booking API. You supply the restaurant and its phone number; we call or text it, get a yes or a no, and report back. We are not the restaurant. Nothing is a reservation until the restaurant says it is.
Types
type TableStatus =
| "requested" | "contacting"
| "confirmed" | "declined" | "no_answer" | "cancelled" | "failed";
The last five are terminal and never change again.
Endpoints
| MCP tool | Scope | Cost | REST |
|---|---|---|---|
request_table |
write | free | POST /c/tables/v1/requests |
get_table_request |
read | free | GET /c/tables/v1/requests/{request_id} |
list_table_requests |
read | free | GET /c/tables/v1/requests?limit=&cursor= |
cancel_table_request |
write | free | POST /c/tables/v1/requests/{request_id}/cancel |
get_balance |
read | free | GET /c/tables/v1/balance |
create_topup_link |
read | free | POST /c/tables/v1/topups |
delete_my_data |
write | free | DELETE /c/tables/v1/me |
- request_table - in
restaurant_name,restaurant_phone(E.164, US only),party_size(1 to 20),requested_at(ISO with its UTC offset, in the future),diner_name, optionaldiner_phone,notes(<= 200 characters) andidempotency_key. Out{ "request_id", "status": "contacting", "channel", "expires_at", "price_cents_if_confirmed", "balance_cents", "tables_balance_cents" }. - get_table_request - out the record plus
events[]. This is how you find out whether the restaurant answered. - cancel_table_request - allowed only while
requestedorcontacting. Free. - get_balance and create_topup_link - as in mail and fax, plus
tables_balance_cents(leftover credit from a table pass bought before tables became free).create_topup_linktakes exactly one ofamount_centsorfax_bundle_cents. Neither is needed to ask for a table.
Asking for a table is free for the person and their agent, whatever the
restaurant answers. request_table needs no credit and never returns 402;
price_cents_if_confirmed is always 0. Restaurants pay us to be bookable,
$25.00 a month or $150.00 a year.
A request expires an hour before the table or two hours after it was made, whichever comes first, floored at ten minutes. There is no retry.
Two further routes under /c/tables/v1 are not tools and take no
API key: POST /c/tables/v1/restaurants/opt-in and
GET /c/tables/v1/restaurants/count are the restaurant sign-up
form and its counter on for restaurants.
| Item | Price |
|---|---|
| A restaurant table the restaurant confirms | Free |
| A table the restaurant declines, or never answers | Free |
| Cancelling a table request | Free |
Shipping labels
US shipping labels through our provider, EasyPost: quote a package, buy a label, make a return label, book a USPS pickup, track any package from any carrier, and void an unused label. Shipping spends ordinary credit only.
Types
ShipAddress is the mail Address with name required, plus optional
phone and email. Parcel is
{ "weight_oz", "length_in"?, "width_in"?, "height_in"?, "preset"? }: the
weight is always required, the three dimensions come together or not at all,
and preset (envelope, small_box, medium_box, large_box,
flat_rate_envelope, small_flat_rate_box, medium_flat_rate_box,
large_flat_rate_box) replaces the dimensions.
Endpoints
| MCP tool | Scope | Cost | REST |
|---|---|---|---|
get_shipping_rates |
read | free | POST /c/ship/v1/rates |
buy_label |
write | the quote's price_cents |
POST /c/ship/v1/labels |
create_return_label |
write | the quote's price_cents |
POST /c/ship/v1/returns |
get_shipment |
read | free | GET /c/ship/v1/shipments/{shipment_id} |
list_shipments |
read | free | GET /c/ship/v1/shipments?limit=&cursor= |
track_package |
read | free (30 new numbers/day) | GET /c/ship/v1/track?tracking_code=&carrier= |
void_label |
write | refund on carrier confirmation | POST /c/ship/v1/shipments/{shipment_id}/void |
get_pickup_options |
read | free | POST /c/ship/v1/pickups/options |
schedule_pickup |
write | free for USPS; otherwise the quoted price | POST /c/ship/v1/pickups |
cancel_pickup |
write | refunds a paid pickup | POST /c/ship/v1/pickups/{pickup_id}/cancel |
get_balance |
read | free | GET /c/ship/v1/balance |
create_topup_link |
read | free | POST /c/ship/v1/topups |
delete_my_data |
write | free | DELETE /c/ship/v1/me |
- get_shipping_rates - in
{ "from", "to", "parcel", "return_label"? }. Checks both addresses with the carrier (an undeliverabletois400withfield: "to"), then returns up to sixquotes, cheapest first, each{ "quote_id", "carrier", "service", "delivery_days", "price_cents", "retail_cents", "qr_code_available" }, plusexpires_at(60 minutes) andbalance_cents. - buy_label / create_return_label - in
{ "quote_id", "confirm": true, "qr_code"?, "idempotency_key"? }. A quote is single-use.qr_codedefaults totruefor returns and applies to USPS only. Out the shipment withlabel_url(PDF) andqr_code_url(PNG for the USPS counter). A carrier refusal is502after an automatic refund. - void_label - in
{ "shipment_id", "confirm": true }, only for an unscanned label. It setsrefund_status: "submitted"; credits return when the carrier confirms. USPS: within 30 days, at least 15 days to process. - get_pickup_options / schedule_pickup / cancel_pickup - a pickup at the shipment's origin in a window you give. USPS Package Pickup is free.
| Item | Price |
|---|---|
| Shipping label or return label: the carrier's rate x 1.42, plus $1.50 | quoted before you buy |
| Shipping quote | Free |
| Tracking a package, any carrier | Free |
| USPS pickup from your door | Free |
| Voiding an unused label | refunded when the carrier confirms |
A label is priced ceil(rate_cents * 142 / 100) + 150 from the carrier's rate. See
pricing for the comparison with the post office counter.
Photo prints
Photos printed by a photo lab and posted to a US address: 4x6, 5x7 and 8x10 prints, a 12x16 canvas, a custom T-shirt with the photo on the front and a custom 11oz mug with the photo wrapped around it. Shirts and mugs are printed on demand and are not returnable except when damaged or misprinted. Quote first, then order the quote.
Types
type PrintStatus = "submitted" | "in_production" | "shipped" | "cancelled";
type PrintProduct = "4x6" | "5x7" | "8x10" | "canvas-12x16" | "tshirt" | "mug-11oz";
type ShirtSize = "XS" | "S" | "M" | "L" | "XL" | "2XL" | "3XL";
type ShirtColor = "White" | "Black";
Endpoints
| MCP tool | Scope | Cost | REST |
|---|---|---|---|
list_print_products |
read | free | GET /c/prints/v1/products |
upload_print_image |
write | free | POST /c/prints/v1/images |
quote_prints |
read | free | POST /c/prints/v1/quotes |
order_prints |
write | charged | POST /c/prints/v1/orders |
get_print_order |
read | free | GET /c/prints/v1/orders/{order_id} |
list_print_orders |
read | free | GET /c/prints/v1/orders?limit=&cursor= |
cancel_print_order |
write | refund | POST /c/prints/v1/orders/{order_id}/cancel |
get_balance |
read | free | GET /c/prints/v1/balance |
create_topup_link |
read | free | POST /c/prints/v1/topups |
delete_my_data |
write | free | DELETE /c/prints/v1/me |
- upload_print_image - in
image_base64(JPEG or PNG, up to 20 MB). Outimage_id, the pixel size and how sharp it prints at each size. Deleted after 24 hours unless ordered. - quote_prints - in
items[](product,copies, and one ofimage_idor a public httpsimage_url; atshirtitem also needsshirt_sizeandshirt_color),shipping_method(budget,standard,express) and a USrecipient. Outquote_id,total_cents,breakdown[]andwarnings[]for photos that will print soft or be trimmed. Valid 24 hours. - order_prints - in
quote_idandconfirm: true. Charges exactly the quote'stotal_cents. The samequote_idnever orders twice. - cancel_print_order - only before the lab starts printing; refunds in full.
| Item | Price |
|---|---|
| 4x6 photo print, each | $0.49 |
| 5x7 photo print, each | $1.69 |
| 8x10 photo print, each | $6.49 |
| 12x16 stretched canvas, each | $49.99 |
| Print shipping, budget, for each photo size | $10.99 |
| Print shipping, standard, for each photo size | $18.99 |
| Print shipping, express, for each photo size | $37.99 |
| Canvas shipping, budget or standard, each canvas | $32.99 |
| Canvas shipping, express, each canvas | $58.99 |
| Custom T-shirt, your photo on the front, each | $27.99 |
| Custom 11oz mug, your photo wrapped round, each | $17.99 |
| T-shirt shipping, budget, for the shirts in an order | $10.99 |
| T-shirt shipping, standard, for the shirts in an order | $14.99 |
| T-shirt size 2XL, extra per shirt | $3.00 |
| T-shirt size 3XL, extra per shirt | $6.00 |
| Mug shipping, budget, for the mugs in an order | $8.99 |
| Mug shipping, standard, for the mugs in an order | $14.99 |
| Mug shipping, express, for the mugs in an order | $29.99 |
| Print quote or photo upload | Free |
Greeting cards
Mail a real greeting card to a US address. Two tiers: handwritten, a folded card written by a robot holding a real pen, in a hand-addressed and stamped envelope; and printed, a 6x9 postcard-style card with the message on the back. A printed card is an open postcard: anyone who handles it can read the message, so offer the handwritten tier for sympathy cards and anything private.
Types
type CardStatus =
| "scheduled" | "submitted" | "in_production" | "mailed" | "delivered"
| "returned" | "cancelled" | "failed";
Endpoints
| MCP tool | Scope | Cost | REST |
|---|---|---|---|
list_card_designs |
read | free | GET /c/cards/v1/designs?occasion=&tier= |
list_handwriting_styles |
read | free | GET /c/cards/v1/styles |
preview_card |
read | free | POST /c/cards/v1/quotes |
send_card |
write | charged | POST /c/cards/v1/cards |
get_card |
read | free | GET /c/cards/v1/cards/{card_id} |
list_cards |
read | free | GET /c/cards/v1/cards?limit=&cursor= |
cancel_card |
write | free, refunds | POST /c/cards/v1/cards/{card_id}/cancel |
get_balance |
read | free | GET /c/cards/v1/balance |
create_topup_link |
read | free | POST /c/cards/v1/topups |
delete_my_data |
write | free | DELETE /c/cards/v1/me |
- preview_card - in
design_id,message(1 to 320 characters handwritten, 1 to 500 printed), optionalsignoffandhandwriting_style,toandfromaddresses with names, and at most one ofsend_onorarrive_by(YYYY-MM-DD). Out a single-usequote_idvalid 24 hours, with the price, the dispatch date and the estimated arrival window. Nothing is charged. - send_card - in
{ "quote_id", "confirm": true }. Thequote_idis the idempotency key: a repeat never mails or charges twice. - cancel_card - a
scheduledcard is cancelled and refunded at once; a card already with the provider only while the provider still allows it. - get_balance and create_topup_link - as in mail. Cards spend ordinary credit only.
- delete_my_data - reduces every card's addresses to city, state and ZIP3 and deletes messages and quotes at once. A scheduled card is cancelled and refunded first.
Arrive by a date. arrive_by dispatches 8 days earlier for handwritten
and 7 for printed; we hold the paid card until then, so it can be cancelled
for a full refund until it leaves. Addresses and messages are deleted 30 days
after a card is mailed.
| Item | Price |
|---|---|
| Greeting card, printed 6x9 (an open postcard) | $3.99 |
| Greeting card, handwritten with a real pen, in an envelope | $8.99 |
| Card preview and quote | Free |
| Cancelling a card before it is mailed (full refund) | Free |
Signatures
Get a PDF signed by up to 5 people, or sign one yourself,
under the US ESIGN Act and UETA. Our own signing page, no e-signature partner.
We send no email: send_envelope returns each signer's signing_url, and
the agent delivers it from the human's own email connector, so the request
comes from someone the signer knows. Full details, including the documents
that may not be sent, are in the connector brief.
Endpoints
| MCP tool | Scope | Cost | REST |
|---|---|---|---|
create_envelope |
write | free (returns the quote) | POST /c/sign/v1/envelopes |
send_envelope |
write | charged | POST /c/sign/v1/envelopes/{envelope_id}/send |
get_envelope |
read | free | GET /c/sign/v1/envelopes/{envelope_id} |
list_envelopes |
read | free | GET /c/sign/v1/envelopes?limit=&cursor=&status= |
remind_signer |
write | free | POST /c/sign/v1/envelopes/{envelope_id}/signers/{signer_id}/link |
void_envelope |
write | free (refund if nobody opened it) | POST /c/sign/v1/envelopes/{envelope_id}/void |
get_signed_document |
read | free | GET /c/sign/v1/envelopes/{envelope_id}/document |
delete_envelope |
write | free | DELETE /c/sign/v1/envelopes/{envelope_id} |
get_balance |
read | free | GET /c/sign/v1/balance |
create_topup_link |
read | free | POST /c/sign/v1/topups |
delete_my_data |
write | free | DELETE /c/sign/v1/me |
- create_envelope - in
title, exactly one ofdocument_url(https) ordocument_base64, andsigners(1 to 5, eachname,email, optionalorder), orself_sign: truewithsigner_name. Optionalfields,message,expires_in_days(1 to 90) andretention_days(30, 90, 365 or 1095). Out: the draft and aquotewithquote_idandtotal_cents, valid 24 hours. - send_envelope - in
envelope_idandquote_id. Charges exactly the quoted amount, once. Out: each signer with theirsigning_url. Links are shown only here and fromremind_signer. - void_envelope - full refund if no signer has opened their link yet; otherwise free but not refunded.
- get_signed_document - a download link for the finished PDF, valid 15 minutes.
| Item | Price |
|---|---|
| Signature envelope, 1 to 5 signers | $1.99 |
| Self-sign envelope, you are the only signer | $0.99 |
| Your first self-sign envelope | Free |
| Preparing an envelope and its quote, reminders, downloads | Free |
Bookings
Free for the person booking. No call in this connector deducts credits. Merchants pay $29.00 a month to be listed; see for businesses.
Endpoints
| MCP tool | Scope | REST |
|---|---|---|
search_providers |
read | POST /c/booking/v1/providers/search |
list_services |
read | GET /c/booking/v1/providers/{provider_id}/services |
get_availability |
read | POST /c/booking/v1/providers/{provider_id}/availability |
create_booking |
write | POST /c/booking/v1/bookings |
get_booking |
read | GET /c/booking/v1/bookings/{booking_id} |
cancel_booking |
write | POST /c/booking/v1/bookings/{booking_id}/cancel |
list_my_bookings |
read | GET /c/booking/v1/bookings?limit=&cursor= |
- search_providers - in
{ "query": string, "city"?: string, "state"?: string, "zip"?: string, "limit"?: 1..20 }, out{ "providers": [...] }withprovider_id,display_name,categories,address,timezone,next_available_atandservices_preview. Matching is a case-insensitive keyword match over service names and categories, filtered by city and state or ZIP prefix. Radius search does not exist in v0. - list_services - out
{ "services": [...] }withservice_id,name,duration_min,price_cents, optionaldescriptionandteam_member_ids. Cached, refreshed when older than ten minutes. - get_availability - in
{ "service_id", "date_from": "YYYY-MM-DD", "date_to": "YYYY-MM-DD", "team_member_id"? }, a window of at most 14 days. Out{ "slots": [...] }, at most 50, each withstart_at(ISO with offset),team_member_idandduration_min. - create_booking - in
provider_id,service_id,start_at, optionalteam_member_id, acustomerblock (given_name,family_name,email,phonein E.164), optionalnote(<= 200 characters) andidempotency_key. Outbooking_id,status(pending,confirmedorcancelled),confirmation,start_at,end_at,provider,serviceandcancellation_policy. A new booking is a request: it comes backpending, the business accepts it in their own Square calendar, usually the same day, andconfirmationis the sentence to read to the person. - get_booking - out the same booking object. It re-reads the status from the business's calendar, so this is how you find out whether a pending request has been accepted.
- cancel_booking - in
{ "booking_id", "reason"? }, out the booking withstatus: "cancelled". - list_my_bookings - in
{ "limit"?, "cursor"? }, out{ "items": [booking], "next_cursor"? }for the calling account only.
Merchant endpoints
These are for business owners in a browser, not for agents:
GET https://api.noerrands.com/c/booking/merchant/connect?merchant_email=&return_to=starts Square OAuth.GET https://api.noerrands.com/c/booking/merchant/callbackis the OAuth redirect target. It sends a browser on to /for-businesses/connected withmerchant,statusandtrial_untilon the query; a caller sendingAccept: application/jsongets the JSON body instead, including the merchant session token.GET/PATCH https://api.noerrands.com/c/booking/merchant/meis merchant self-service, authenticated with a merchant session token rather than an API key.GETalso returnsbilling_status,trial_untilandplan_url.POST https://api.noerrands.com/c/booking/merchant/manage-linkwith{ "email": "..." }asks for a single-use, 24-hour link to /for-businesses/manage, the settings page a business uses to check its listing and disconnect. It always answers202and never says whether the address is connected.POST https://api.noerrands.com/c/booking/merchant/disconnectrevokes at Square and deletes everything we hold about that business.POST https://api.noerrands.com/c/booking/square/webhookreceives Square's event notifications. We subscribe tooauth.authorization.revoked, so a business that disconnects inside Square is deleted here within seconds.
Test it with curl
Set your key once:
export API_KEY="ne_live_your_key_here"
export MAIL="https://api.noerrands.com/c/mail/v1"
export FAX="https://api.noerrands.com/c/fax/v1"
export BOOKING="https://api.noerrands.com/c/booking/v1"
Is the service up?
curl -s https://api.noerrands.com/health
Check the account and the balance:
curl -s "$MAIL/me" -H "Authorization: Bearer $API_KEY"
curl -s "$MAIL/balance" -H "Authorization: Bearer $API_KEY"
Check a postal address (free):
curl -s "$MAIL/addresses/verify" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"address":{"name":"Ada Lovelace","line1":"1 Main St","city":"Austin","state":"TX","zip":"78701"}}'
Get a price (free):
curl -s "$MAIL/estimate" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"kind":"letter","pages":2,"color":false,"certified":false}'
curl -s "$FAX/estimate" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"pages":3}'
Send a letter (this costs money):
curl -s "$MAIL/letters" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to":{"name":"Ada Lovelace","line1":"1 Main St","city":"Austin","state":"TX","zip":"78701"},
"from":{"name":"Grace Hopper","line1":"2 Oak Ave","city":"Denver","state":"CO","zip":"80202"},
"subject":"Hello",
"body_markdown":"Dear Ada,\n\nThank you.\n\nGrace",
"idempotency_key":"letter-to-ada-2026-09-21"
}'
Send a postcard (this costs money):
curl -s "$MAIL/postcards" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to":{"name":"Ada Lovelace","line1":"1 Main St","city":"Austin","state":"TX","zip":"78701"},
"from":{"name":"Grace Hopper","line1":"2 Oak Ave","city":"Denver","state":"CO","zip":"80202"},
"front":{"text":"Greetings from Denver"},
"message":"Wish you were here.",
"idempotency_key":"postcard-to-ada-2026-09-21"
}'
Send a fax (this costs money):
curl -s "$FAX/faxes" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to_number":"+14155550123",
"recipient_name":"Records Office",
"pdf_url":"https://example.com/intake-form.pdf",
"cover_note":"Intake form for Ada Lovelace.",
"idempotency_key":"fax-to-records-2026-09-21"
}'
Find a business and see its open slots (free):
curl -s "$BOOKING/providers/search" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"haircut","city":"Austin","state":"TX","limit":5}'
curl -s "$BOOKING/providers/prv_01H8X/services" -H "Authorization: Bearer $API_KEY"
curl -s "$BOOKING/providers/prv_01H8X/availability" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"service_id":"svc_01","date_from":"2026-09-24","date_to":"2026-09-26"}'
Book it (free, but it puts a real person in a real calendar):
curl -s "$BOOKING/bookings" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"provider_id":"prv_01H8X",
"service_id":"svc_01",
"start_at":"2026-09-24T14:00:00-05:00",
"customer":{"given_name":"Ada","family_name":"Lovelace","email":"ada@example.com","phone":"+14155550123"},
"idempotency_key":"haircut-2026-09-24"
}'
Check on things:
curl -s "$MAIL/mail/ml_01H8X" -H "Authorization: Bearer $API_KEY"
curl -s "$FAX/faxes/fx_01H8X" -H "Authorization: Bearer $API_KEY"
curl -s "$BOOKING/bookings?limit=5" -H "Authorization: Bearer $API_KEY"
Add credits:
curl -s "$MAIL/topups" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"amount_cents":249}'
On Windows PowerShell, use Invoke-RestMethod or wrap the JSON in single
quotes with curl.exe rather than the curl alias.
Known gaps in v0
- Email addresses on key creation are not verified.
- Mail is United States only; fax is United States and Canada; bookings are United States only; signatures are for use in the United States.
- Signature envelopes send no email: the agent delivers each signing link from the human's own email connector.
- Mail cannot be cancelled once it is submitted to the print provider, and a fax cannot be recalled once transmitted.
- Booking search has no radius filter. Supply a city and state, or a ZIP.
- There is no reschedule call. Cancel and rebook.
- Merchant listings are billed monthly through a Stripe subscription; there is no customer portal link yet, so cancellations go through support.
- Per-call payment over Stripe's Machine Payments Protocol is behind a flag and may return a stubbed challenge.
Support
Email support@noerrands.com.