{"openapi":"3.1.0","info":{"title":"Paper Owl Mail API","version":"0.1.0","summary":"Mail one printed letter, or USPS Certified Mail, to one US address. The user reviews and pays before anything is printed.","description":"Paper Owl Mail prints and mails one letter to one US address (the 50 states and DC). Create a draft, show the user both addresses, the pages and the price, then either charge an in-chat approved Stripe shared payment token (send) or send the user to the review page to pay with Stripe Checkout. A paid letter is held 15 minutes, when cancelling refunds it in full; then it goes to print. Payment terms: First-Class letter $2.99, Certified Mail $10.99, Certified Mail with electronic return receipt $13.99; each covers up to 3 pages, plus $0.25 for each page after that, up to 5 pages; a Certified Mail letter from a PDF can be up to 4 pages. The user is charged only when they approve the exact total. A paid letter can be cancelled for a full refund for 15 minutes, then it goes to print. If the printer rejects a letter, the full price is refunded automatically. A letter that has reached USPS is not refundable, including one USPS returns. An unpaid draft can be cancelled free at any time and expires after 24 hours. Not for advertising, bulk mail, bill-like solicitations, debt collection or political campaign mail.","contact":{"name":"Paper Owl Mail support","email":"support@sendpaperowl.com","url":"https://sendpaperowl.com/#support"},"termsOfService":"https://sendpaperowl.com/legal/terms","x-logo":{"url":"https://api.sendpaperowl.com/brand/paper-owl-icon-512.png"},"x-muse":{"name":"Paper Owl Mail","company":"Vectis Studio LLC","description":"Mail a printed letter, or USPS Certified Mail, to any address in the 50 states and DC from chat. You see every page, both addresses and the price, and approve the charge before anything is printed.","websiteUrl":"https://sendpaperowl.com","docsUrl":"https://api.sendpaperowl.com/mail/muse.md","supportEmail":"support@sendpaperowl.com","privacyPolicyUrl":"https://sendpaperowl.com/legal/privacy","termsUrl":"https://sendpaperowl.com/legal/terms","iconUrl":"https://api.sendpaperowl.com/brand/paper-owl-icon-512.png","examplePrompts":["Mail this letter to my landlord at 123 Main St, Springfield, IL 62701, from me at my home address.","Send my signed notice by Certified Mail with a return receipt to the county clerk.","Has my letter to the records office been mailed yet?"],"auth":"none","serverUrl":"https://api.sendpaperowl.com/mail/mcp"}},"servers":[{"url":"https://api.sendpaperowl.com/mail/v1"}],"externalDocs":{"description":"Paper Owl Mail docs","url":"https://api.sendpaperowl.com/mail/docs"},"security":[],"tags":[{"name":"Mail","description":"Draft, pay for, mail, cancel and track a letter."}],"paths":{"/drafts":{"post":{"operationId":"create_mail_draft","tags":["Mail"],"summary":"Create a letter draft and get the price","description":"Prepare one printed letter to one US address (the 50 states and DC) and get its price. This creates an unpaid draft only: nothing is printed and nothing is charged. Provide \"from\" (the user's own real name and a US mailing address where they receive mail; printed as the return address; ask the user, never guess), \"to\" (the recipient's name and address), \"service\" (first_class, certified or certified_return_receipt), and exactly one letter source: \"text\" (plain text or simple Markdown), \"pdf_base64\", or \"pdf_url\" (public https, 10 MB max). Both addresses are checked against USPS records; an undeliverable address is refused, and a missing apartment or suite number must be added. Letters are black and white, single-sided, at most 5 pages; a Certified Mail letter from a PDF at most 4 pages. Returns a draft_id, both addresses as they will print, any USPS changes (address_changes), the pages, the price, payment_terms, a preview_url, a review_url, and when the draft expires (24 hours). Read payment_terms to the user word for word, show both addresses and any changes, the service, pages and price, and offer the preview link before asking for payment. Then either ask the user to approve the charge in chat and call send_mail, or, if your client cannot take payments, give the user the review_url. Reviewers: a recipient named \"Paper Owl Mail Test Desk\", at any address, is the test path: charged, never printed, refunded in full automatically. Will not: send to more than one address, mail outside the 50 states and DC, or send advertising, bulk mail, bill-like solicitations, debt collection or political campaign mail. Payment terms: First-Class letter $2.99, Certified Mail $10.99, Certified Mail with electronic return receipt $13.99; each covers up to 3 pages, plus $0.25 for each page after that, up to 5 pages; a Certified Mail letter from a PDF can be up to 4 pages. The user is charged only when they approve the exact total. A paid letter can be cancelled for a full refund for 15 minutes, then it goes to print. If the printer rejects a letter, the full price is refunded automatically. A letter that has reached USPS is not refundable, including one USPS returns. An unpaid draft can be cancelled free at any time and expires after 24 hours.","x-safety":{"side_effects":"Checks both addresses with USPS records and creates an unpaid draft. Prints nothing, charges nothing."},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique value per logical request, for example a UUID. Retrying with the same key and body within 24 hours returns the first response instead of repeating the action.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMailDraftInput"}}}},"responses":{"201":{"description":"Draft created. Show the user both addresses, any changes, the pages and the price, and offer preview_url.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Letter"}}}},"400":{"description":"The request was invalid, or an address is not one we can mail to. See error.code and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"The document is larger than 10 MB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"An address is undeliverable according to USPS, or the pdf_url could not be downloaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited, or the recipient address has had the most letters allowed recently. Retry after the number of seconds in the Retry-After header when given.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Payments or address checks are temporarily unavailable. Nothing was charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/drafts/{id}":{"get":{"operationId":"get_mail_status","tags":["Mail"],"summary":"Get letter status","description":"Look up a letter by draft_id. Read only; charges nothing. Returns the status (draft, paid, held, submitted, mailed, delivered, returned, failed, refunded, cancelled or expired), both addresses, the service, pages, price, when the free-cancel hold ends, the estimated print date, the USPS tracking number for certified letters, the refund status, and a next_step sentence you can relay to the user. During the hold, check again after it ends. Once the letter is at the printer or with USPS, check about once a day.","x-safety":{"side_effects":"None. Read only."},"parameters":[{"name":"id","in":"path","required":true,"description":"Draft ID returned when the draft was created.","schema":{"type":"string","pattern":"^mail_[A-Za-z0-9_-]{32}$"}}],"responses":{"200":{"description":"Current status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Letter"}}}},"400":{"description":"The request was invalid, or an address is not one we can mail to. See error.code and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No draft with that ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited, or the recipient address has had the most letters allowed recently. Retry after the number of seconds in the Retry-After header when given.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/drafts/{id}/send":{"post":{"operationId":"send_mail","tags":["Mail"],"summary":"Charge the user and mail the letter","description":"CHARGES THE USER MONEY. Charges exactly the price quoted by create_mail_draft, then holds the letter for 15 minutes, during which the user can cancel it with cancel_mail for a full refund; after that it goes to print. Only call this after the user has seen both addresses, the service, the pages and the price, has approved that exact charge in chat, and has confirmed they are the sender named on the letter, or authorized to send for the business named on the letter, the return address is where that sender receives mail, and the letter is not advertising, a bill-like solicitation, debt collection or political campaign mail. Pass the draft_id, the Stripe shared payment token (spt_...) granted by that approval, and attest_sender_and_content: true. Never invent or reuse a token. The charge is never more than the quote. If the charge fails, nothing is printed and the draft stays unpaid so the user can try again. Safe to retry: calling it again for the same draft never charges twice. Set dry_run: true to check the draft and the approval without charging. If your client cannot take payments in chat, do not call this; give the user the review_url instead. Payment terms: First-Class letter $2.99, Certified Mail $10.99, Certified Mail with electronic return receipt $13.99; each covers up to 3 pages, plus $0.25 for each page after that, up to 5 pages; a Certified Mail letter from a PDF can be up to 4 pages. The user is charged only when they approve the exact total. A paid letter can be cancelled for a full refund for 15 minutes, then it goes to print. If the printer rejects a letter, the full price is refunded automatically. A letter that has reached USPS is not refundable, including one USPS returns. An unpaid draft can be cancelled free at any time and expires after 24 hours.","x-safety":{"side_effects":"Charges the user the quoted price. The letter is held 15 minutes (cancellable with a full refund), then printed and mailed, which cannot be undone.","requires_user_confirmation":true,"idempotent":"Repeating the call for the same draft never charges twice."},"parameters":[{"name":"id","in":"path","required":true,"description":"Draft ID returned when the draft was created.","schema":{"type":"string","pattern":"^mail_[A-Za-z0-9_-]{32}$"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique value per logical request, for example a UUID. Retrying with the same key and body within 24 hours returns the first response instead of repeating the action.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMailBody"}}}},"responses":{"200":{"description":"Paid and held, or already paid earlier (no second charge).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Letter"}}}},"400":{"description":"The request was invalid, or an address is not one we can mail to. See error.code and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The payment was declined. Nothing was charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No draft with that ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The letter is not in a state that allows this action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The draft expired before it was paid. Nothing was charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited, or the recipient address has had the most letters allowed recently. Retry after the number of seconds in the Retry-After header when given.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Payments or address checks are temporarily unavailable. Nothing was charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/drafts/{id}/cancel":{"post":{"operationId":"cancel_mail","tags":["Mail"],"summary":"Cancel a draft, or a paid letter during its hold","description":"Cancel a letter by draft_id. Before payment: cancels the draft, nothing is charged. After payment and within the 15-minute hold: cancels the letter and refunds the full price. After the hold the letter has gone to print and cannot be cancelled; the call says so. Calling it again on a cancelled letter is harmless. Set dry_run: true to check whether it can still be cancelled without cancelling it.","x-safety":{"side_effects":"Cancels an unpaid draft (nothing charged), or a paid letter during its 15-minute hold with a full refund. Repeating it is harmless."},"parameters":[{"name":"id","in":"path","required":true,"description":"Draft ID returned when the draft was created.","schema":{"type":"string","pattern":"^mail_[A-Za-z0-9_-]{32}$"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Optional. A unique value per logical request, for example a UUID. Retrying with the same key and body within 24 hours returns the first response instead of repeating the action.","schema":{"type":"string","maxLength":255}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelMailBody"}}}},"responses":{"200":{"description":"Cancelled (or already cancelled).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Letter"}}}},"400":{"description":"The request was invalid, or an address is not one we can mail to. See error.code and error.message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No draft with that ID.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The letter is not in a state that allows this action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited, or the recipient address has had the most letters allowed recently. Retry after the number of seconds in the Retry-After header when given.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"schemas":{"CreateMailDraftInput":{"type":"object","properties":{"from":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":40,"description":"Full name of the person, as it should print. Required. Ask the user; never guess."},"company":{"description":"Company or organization, printed under the name. Optional.","type":"string","minLength":1,"maxLength":40},"line1":{"type":"string","minLength":1,"maxLength":64,"description":"Street address, for example \"210 King St\"."},"line2":{"description":"Apartment, suite or unit, for example \"Apt 4\". Optional, but required when the building has units.","type":"string","minLength":1,"maxLength":64},"city":{"type":"string","minLength":1,"maxLength":60,"description":"City."},"state":{"type":"string","minLength":2,"maxLength":2,"description":"Two-letter state code, for example \"CA\", or \"DC\". The 50 states and DC only."},"zip":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$","description":"ZIP code, 5 digits or ZIP+4."}},"required":["name","line1","city","state","zip"],"additionalProperties":false,"description":"The sender: the user's own real name and a US mailing address where they receive mail. Printed as the return address."},"to":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":40,"description":"Full name of the person, as it should print. Required. Ask the user; never guess."},"company":{"description":"Company or organization, printed under the name. Optional.","type":"string","minLength":1,"maxLength":40},"line1":{"type":"string","minLength":1,"maxLength":64,"description":"Street address, for example \"210 King St\"."},"line2":{"description":"Apartment, suite or unit, for example \"Apt 4\". Optional, but required when the building has units.","type":"string","minLength":1,"maxLength":64},"city":{"type":"string","minLength":1,"maxLength":60,"description":"City."},"state":{"type":"string","minLength":2,"maxLength":2,"description":"Two-letter state code, for example \"CA\", or \"DC\". The 50 states and DC only."},"zip":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$","description":"ZIP code, 5 digits or ZIP+4."}},"required":["name","line1","city","state","zip"],"additionalProperties":false,"description":"The recipient's name and US mailing address. A recipient named \"Paper Owl Mail Test Desk\" is the reviewer test path: any address works, nothing is printed, and the charge is refunded automatically."},"service":{"type":"string","enum":["first_class","certified","certified_return_receipt"],"description":"first_class (a First-Class letter), certified (USPS Certified Mail) or certified_return_receipt (Certified Mail with an electronic return receipt)."},"text":{"description":"The letter as plain text or simple Markdown (headings, lists, bold). Rendered to US Letter pages with room for the address at the top of page 1. Use a form feed character to force a page break.","type":"string","minLength":1,"maxLength":100000},"pdf_base64":{"description":"The letter as a base64 encoded PDF, 10 MB maximum. A blank address page is added in front.","type":"string","maxLength":13981030},"pdf_url":{"description":"The letter as a public https URL that returns a PDF, 10 MB maximum. Private and internal addresses are refused.","type":"string","maxLength":2048}},"required":["from","to","service"],"additionalProperties":false},"SendMailBody":{"type":"object","properties":{"payment_token":{"type":"string","minLength":4,"maxLength":256,"description":"The Stripe shared payment token (starts with spt_) granted when the user approved the exact price in chat. Never invent one."},"attest_sender_and_content":{"type":"boolean","const":true,"description":"Must be true. Confirms the user said they are the sender named on the letter, or authorized to send for the business named on the letter, the return address is where that sender receives mail, and the letter is not advertising, a bill-like solicitation, debt collection or political campaign mail."},"dry_run":{"description":"If true, check the draft and the payment approval without charging. Optional; the real call does the same checks first.","type":"boolean"}},"required":["payment_token","attest_sender_and_content"],"additionalProperties":false},"CancelMailBody":{"type":"object","properties":{"dry_run":{"description":"If true, report whether the letter can be cancelled, and whether a refund would follow, without cancelling it.","type":"boolean"}},"additionalProperties":false},"Letter":{"type":"object","properties":{"draft_id":{"type":"string"},"status":{"type":"string","enum":["draft","paid","held","submitted","mailed","delivered","returned","failed","refunded","cancelled","expired"],"description":"draft, paid, held (in the free-cancel window), submitted (at the printer), mailed, delivered, returned, failed, refunded, cancelled or expired."},"service":{"type":"string","enum":["first_class","certified","certified_return_receipt"],"description":"first_class (a First-Class letter), certified (USPS Certified Mail) or certified_return_receipt (Certified Mail with an electronic return receipt)."},"service_name":{"type":"string","description":"The service in words, for example \"Certified Mail\"."},"from":{"type":"object","properties":{"name":{"type":"string"},"company":{"type":"string"},"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"}},"required":["name","line1","city","state","zip"],"additionalProperties":false,"description":"The return address, as it will print."},"to":{"type":"object","properties":{"name":{"type":"string"},"company":{"type":"string"},"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"}},"required":["name","line1","city","state","zip"],"additionalProperties":false,"description":"The recipient address, as it will print (USPS standardized)."},"address_changes":{"type":"array","items":{"type":"object","properties":{"party":{"type":"string","enum":["sender","recipient"]},"field":{"type":"string"},"typed":{"type":"string"},"standardized":{"type":"string"}},"required":["party","field","typed","standardized"],"additionalProperties":false},"description":"What USPS standardization changed from what was typed. Show these to the user before they pay."},"pages":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Pages in the letter."},"sheets":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Sheets in the envelope, counting any address page and the Certified Mail barcode sheet."},"price":{"type":"object","properties":{"amount_cents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Price in cents."},"currency":{"type":"string","const":"usd"},"display":{"type":"string","description":"Price for people, for example $2.99."}},"required":["amount_cents","currency","display"],"additionalProperties":false},"preview_url":{"type":"string","description":"Page that shows every page and the envelope. Offer it to the user before they pay."},"review_url":{"type":"string","description":"Review and pay page for clients without in-chat payments. Also shows live status and the cancel button during the hold."},"expires_at":{"type":"string","description":"When an unpaid draft expires (ISO 8601)."},"created_at":{"type":"string"},"paid_at":{"type":["string","null"]},"hold_ends_at":{"description":"Until when a paid letter can be cancelled for a full refund (ISO 8601).","type":["string","null"]},"estimated_print_date":{"description":"The business day the letter is expected to go to print (YYYY-MM-DD). An estimate, not a promise.","type":["string","null"]},"submitted_at":{"description":"When the letter went to the printer.","type":["string","null"]},"mailed_at":{"type":["string","null"]},"delivered_at":{"type":["string","null"]},"returned_at":{"type":["string","null"]},"failed_at":{"type":["string","null"]},"refunded_at":{"type":["string","null"]},"cancelled_at":{"type":["string","null"]},"tracking_number":{"description":"USPS Certified Mail tracking number, for certified letters once at the printer.","type":["string","null"]},"tracking_url":{"description":"USPS tracking page for the tracking number.","type":["string","null"]},"payment_method":{"anyOf":[{"type":"string","enum":["in_chat","checkout"]},{"type":"null"}]},"payment_reference":{"description":"Stripe's payment reference for this letter once it is paid (for example pi_...): the record of the charge. Give it to support for questions, disputes or refunds.","type":["string","null"]},"support":{"type":"string","description":"Where the user can get help with this letter, ask about a refund or dispute a charge."},"failure_reason":{"description":"Plain-language reason when status is failed or refunded.","type":["string","null"]},"refund_status":{"type":"string","enum":["refunded","pending","not_applicable"]},"refund_reason":{"anyOf":[{"type":"string","enum":["provider_rejected","cancelled_in_window","test_letter","recipient_limit"]},{"type":"null"}],"description":"Why the letter was refunded: provider_rejected, cancelled_in_window, recipient_limit (another letter to the same address was paid for at the same moment and used the last place), or test_letter for the reviewer test path (\"Paper Owl Mail Test Desk\")."},"test_mode":{"type":"boolean","description":"True while Paper Owl Mail is in test mode: no letter is printed or mailed, and payments use Stripe test mode. Tell the user."},"test_letter":{"type":"boolean","description":"True for the reviewer test path (\"Paper Owl Mail Test Desk\"): charged normally, never printed, refunded in full automatically."},"payment_terms":{"description":"For an unpaid draft: the total, how it was calculated, and the payment, cancellation and refund terms, written to be read to the user word for word before they approve the charge. Null once the draft is paid, cancelled or expired.","type":["string","null"]},"next_step":{"type":"string","description":"What the agent should tell the user or do next."}},"required":["draft_id","status","service","service_name","from","to","address_changes","pages","sheets","price","preview_url","review_url","expires_at","created_at","paid_at","hold_ends_at","estimated_print_date","submitted_at","mailed_at","delivered_at","returned_at","failed_at","refunded_at","cancelled_at","tracking_number","tracking_url","payment_method","payment_reference","support","failure_reason","refund_status","refund_reason","test_mode","test_letter","payment_terms","next_step"],"additionalProperties":false},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","description":"Stable machine-readable code.","enum":["INVALID_INPUT","UNSUPPORTED_DESTINATION","ADDRESS_INVALID","ADDRESS_UNDELIVERABLE","DOCUMENT_INVALID","DOCUMENT_TOO_LARGE","TOO_MANY_PAGES","URL_NOT_ALLOWED","FETCH_FAILED","NOT_FOUND","DRAFT_EXPIRED","INVALID_STATE","ATTESTATION_REQUIRED","PAYMENT_TOKEN_INVALID","PAYMENT_DECLINED","PAYMENT_IN_PROGRESS","CHARGE_EXCEEDS_QUOTE","RATE_LIMITED","PAYMENTS_UNAVAILABLE","SENDING_UNAVAILABLE","INTERNAL"]},"message":{"type":"string","description":"Plain-language explanation that can be shown to the user."},"details":{"type":"object","additionalProperties":true}}}}}}}}