# UploadLetters Print & Mail API # Start here UploadLetters prints, prepares and mails business documents from your software. API access has no separate subscription, integration or usage fee. The mailing and ancillary services you order are billable. ## The main integration 1. Create a draft batch with recipient addresses, mailing options and PDF filenames. 2. Upload the matching PDF files. 3. Wait for preparation and check every recipient and file. 4. Explicitly submit the batch for charging and production. 5. Retrieve statuses, document images and available tracking records. A batch groups recipient records. A recipient normally represents one mailed letter. PDF uploads supply document content; uploading a PDF does not create a recipient. The `shadow` option can create an additional billable First-Class copy for an eligible Certified Mail recipient. ## Choose the right interface Use an API key in the `x-api-key` header for the public batch workflow. The separate `/batches/import/*` routes use a web-application session token. They support an import wizard and are not the starting point for a public API-key integration. ## Before running an example The documented server is `https://api.uploadletters.com`. There is no sandbox. Do not assume a sample request is harmless. Use approved data, keep credentials server-side and stop before fulfillment until the intended mailing has been reviewed. The guides describe the confirmed API workflow. Examples are documentation, not executed test mailings. --- # Authentication and credentials Get an API key from the settings in your UploadLetters account. Send it on each public request: ```http x-api-key: YOUR_API_KEY Accept: application/json ``` Keep the key in a server-side secret or environment variable. Never put it in browser JavaScript, a shared prompt, a repository or a support screenshot. A public marketing page should link to this guide without asking for a credential. Use `Content-Type: application/json` when posting recipient JSON. For PDF uploads, let your HTTP client construct the multipart Content-Type and boundary. Authentication is still `x-api-key`. A 401 response means authentication was not accepted. A 403 can mean the account lacks permission for an optional feature. Enabling the account feature and using the correct JSON field are separate requirements. The import-wizard routes use Bearer session authentication. Do not substitute an API key into those routes or try to manufacture a login token. Use the established company key-management process. No session-token issuance or rotation interface is supplied by this public API-key guide. --- # Send your first mailing This example prepares one First-Class letter. It uses demonstration addresses, not deliverable test destinations. Replace both addresses and inspect the PDF before submitting any real mailing. ## 1. Set local variables ```bash export UPLOADLETTERS_API_KEY='REPLACE_WITH_YOUR_KEY' export UPLOADLETTERS_BASE_URL='https://api.uploadletters.com' ``` Keep `sample-letter.pdf` in the current directory. Use the provided `examples/create-batch.json`, replacing demonstration data first. ## The recipient payload Save this as `examples/create-batch.json`. These are demonstration addresses; replace them before use. ```json { "address_verification_type": "NONE", "batch_type": "letter", "recipients": [ { "unique_id": "example-001", "letter_id": "example-letter-001", "address": { "first_name": "Example", "last_name": "Recipient", "address_line_1": "123 Example Street", "city": "Frisco", "state": "TX", "zip": "75036" }, "return_address": { "company": "Example Business", "address_line_1": "456 Example Avenue", "city": "Frisco", "state": "TX", "zip": "75036" }, "mailing_options": { "service_type": "fc", "envelope_type": "10", "is_colored": false, "is_double_sided": false }, "pdf_file_config": { "pdf_name": "sample-letter.pdf" } } ] } ``` ## 2. Create the draft ```bash curl --fail-with-body "$UPLOADLETTERS_BASE_URL/batches" -H "x-api-key: $UPLOADLETTERS_API_KEY" -H 'Content-Type: application/json' --data-binary @examples/create-batch.json ``` A successful response contains `is_successful: true` and `batch_id`. Copy `batch_id` into the variable below. In route names, the same identifier is called `processId`. ```bash export UPLOADLETTERS_BATCH_ID='COPY_BATCH_ID_HERE' ``` Check `invalid_letters` even when HTTP status is 200. Its keys are zero-based input indexes: `2` identifies the third submitted recipient. Valid recipients can be accepted while others are rejected. Do not continue until you have reconciled every intended recipient. ## 3. Upload the PDF ```bash curl --fail-with-body -X PATCH "$UPLOADLETTERS_BASE_URL/batches/$UPLOADLETTERS_BATCH_ID/letters" -H "x-api-key: $UPLOADLETTERS_API_KEY" -F 'letters[]=@sample-letter.pdf;type=application/pdf' ``` The uploaded filename must exactly match `pdf_file_config.pdf_name`. Repeat the `letters[]` field to upload multiple uniquely named files. Do not send base64 JSON or manually set a multipart boundary. ## 4. Verify preparation ```bash curl --fail-with-body "$UPLOADLETTERS_BASE_URL/batches/$UPLOADLETTERS_BATCH_ID" -H "x-api-key: $UPLOADLETTERS_API_KEY" curl --fail-with-body "$UPLOADLETTERS_BASE_URL/batches/$UPLOADLETTERS_BATCH_ID/recipients" -H "x-api-key: $UPLOADLETTERS_API_KEY" ``` Wait for outstanding background work to settle. Inspect `active_bg_tasks_count`, `batch.in_loading`, `current_letters_count` and `minimum_letters_count` together. Reconcile the expected recipient count, `invalid_letters`, recipient `error_message`, `total_not_mapped_recipients` and `missed_images`. Require no unresolved recipient errors, no unmapped recipients and no missing files. Handle missing counters as unknown, not zero. Do not use `onlyValid`, which removes failure information. Review any address changes and all service options before fulfillment. ## 5. Submit for charging and production This is the production boundary. Run it only after approving the actual recipients, documents, options and charges. The request has no body. ```bash curl --fail-with-body -X PUT "$UPLOADLETTERS_BASE_URL/batches/$UPLOADLETTERS_BATCH_ID/fulfill" -H "x-api-key: $UPLOADLETTERS_API_KEY" ``` A successful response queues the batch for charging and fulfillment. It does not mean the wallet has already been charged or the mail has entered the carrier network. Editing is blocked after fulfillment is requested. Poll for status and reconcile notifications. With manual review enabled, fulfillment returns 422 and moves the draft to Incomplete Orders instead; review and pay in the application. Read errors-retries.md before recovery. ## 6. Read the mailing records ```bash curl --fail-with-body "$UPLOADLETTERS_BASE_URL/batches/$UPLOADLETTERS_BATCH_ID/letters/paged?page=1&perPage=25" -H "x-api-key: $UPLOADLETTERS_API_KEY" ``` Available fields and artifacts depend on processing stage and service. Read the tracking and records guide before interpreting a status as delivery. --- # Batches, recipients and identifiers ## Understand the identifiers | Name | Meaning | | --- | --- | | `batch_id` | Identifier returned by creating a batch. | | `{processId}` | Path parameter for that same batch identifier. | | `batch.order_id` | Customer-facing numeric order reference when present. | | `unique_id` | Your string reference for reconciling a recipient. | | `letter_id` in recipient input | Your optional reference, echoed back. | | `Letter.id` in output | UploadLetters internal letter identifier. | Neither customer reference is documented as an idempotency key. Do not assume duplicate values prevent duplicate mail. ## Recipient input Each letter recipient needs `address`, `return_address`, `mailing_options` and a `pdf_file_config` for letter-bearing batches. Provide at least one of `first_name`, `last_name` or `company`. Domestic destination addresses need street, city, a valid two-letter state/territory code and ZIP. Supply the return address explicitly even though one phone-field description mentions a default. Use `unique_id` as a string, including when your own identifier contains only digits. Do not send response-only `id`, `full_name` or `error_message` fields. Unknown input fields can be ignored silently; a typo may not produce a helpful rejection. ## Create versus edit Batch-level `batch_type`, `same_day_mailing`, `certificate_of_mailing` and `restricted_delivery` belong on creation. The published contract says these flags are inherited and ignored on recipient PATCH requests. Add or edit draft recipients through the documented PATCH route only while the batch remains editable. Start with about 100 recipients per POST or recipient PATCH as an operational recommendation. The API enforces no fixed recipient-count limit on either request or on the batch. Append additional groups to the same draft before fulfillment. --- # Upload and map PDFs ## One PDF for one recipient Set `pdf_file_config.pdf_name` to the exact uploaded filename. Omit `pdf_page_numbers` to assign the entire file. ## One PDF for multiple recipients Create separate recipients using the same `pdf_name`, with each recipient selecting the intended pages. A selection can be a single page such as `"3"` or an inclusive range such as `"1-3"`. Do not use zero, comma-separated ranges or an array. Range start must be less than range end. Leave internal `pdf_process_type` unset. ## One document for many recipients Multiple recipients can reference the same filename and full document. Each recipient still carries its own address and mailing options. ## Upload mechanics Use `PATCH /batches/{processId}/letters` with multipart field `letters[]`. Filenames must be unique within the batch. Multiple files use repeated `letters[]` fields. The exact filename is the mapping key, so changing capitalization or spelling can leave a recipient unmapped. Build around your company’s Single PDF Max Size setting, which defaults to 15 MB per PDF. A setting of 0 means the company-level per-file limit is disabled. The API does not enforce the previously documented 20 MB total request limit. No fixed cumulative API upload or total-page cap is documented. Per-letter envelope capacities still apply. Coordinate unusually large uploads with UploadLetters. ## Resolve mapping problems The upload response uses `missed_pdf_files`, `extra_pdf_files` and `not_mapped_recipients`. The recipient-read response instead uses `missed_images` and `total_not_mapped_recipients`. These names are different; preserve them in your client. A missing file means a recipient references a filename not uploaded. An extra file means no recipient references that uploaded file. An unmapped recipient may have a filename mismatch, invalid range or processing error. Review all three categories before submitting. The paginated recipient endpoint returns a list, not the complete mapping-readiness report. Use the non-paginated recipient endpoint without `onlyValid` for readiness. Draft changes and uploads can be interleaved, but all content must be reconciled before fulfillment. --- # Choose mailing and printing options | service_type | Service | Envelope value | | --- | --- | --- | | fc | USPS First-Class Mail | 10, 6x9, 9x12; omitted selects by page count | | cm | Certified Mail | 10, 6x9, 9x12; omitted selects by page count | | cm-rre | Certified Mail with Return Receipt Electronic | 10, 6x9, 9x12; omitted selects by page count | | pm | Priority Mail Flat Rate envelope | Leave blank; ignored | | pm-box | Priority Mail Medium Flat Rate Box | Leave blank; ignored | | intl-fc | International First-Class | Explicit 10 or 9x12 required | | rim | International Registered Mail | Explicit 10 or 9x12 required | | FedEx | FedEx Overnight or FedEx 2Day | Explicit overnight or 2day required | ## Envelope capacity | Envelope | Maximum physical sheets, including cover sheet | Uploaded PDF pages, single-sided, without inserts | Uploaded PDF pages, double-sided, without inserts | | --- | --- | --- | --- | | #10 | 5 | 4 | 8 | | 6×9 | 16 | 15 | 30 | | 9×12 | 70 | 69 | 138 | These are physical-sheet limits, not interchangeable PDF-page limits. A return envelope reduces the document allowance by one single-sided page or two double-sided pages; a check consumes additional capacity. Domestic First-Class and Certified Mail can select the envelope automatically when omitted. International uses #10 or 9×12 only and requires an explicit selection. ## International and FedEx batches An entire batch must be domestic or international, and FedEx must be separate from USPS. International requires a recipient country and cannot include return envelopes, checks, same-day mailing or address verification. An omitted international envelope rejects that recipient; it is not auto-selected. For the public API-key workflow, use case-sensitive `service_type: "FedEx"` with explicit `envelope_type: "overnight"` or `"2day"` on FedEx-enabled accounts. Keep FedEx recipients in a separate batch from USPS recipients. Supply `return_address.phone` for the sender and `address.phone` for the recipient. A configured account default can supply the recipient phone. ## Printing API `is_colored` and `is_double_sided` default to false. Check batches use black-and-white, single-sided output. ## Same-day mailing For enabled accounts, set `same_day_mailing: true` when creating the batch. The default cutoff is 11 AM Central, configurable by account. Eligibility is evaluated at charging: API fulfillment/charge processing or after manual approval. Uploading before cutoff alone does not secure same-day mailing. After cutoff, on weekends or applicable carrier holidays, the option is dropped without the surcharge and the order moves to the next business mailing day. When applied, the $1 per-piece surcharge includes extra First-Class copies. International is excluded. Same-day mailing is not same-day delivery. Standard cutoff is 11:59 PM Central for next-business-day mailing. ## Certificate of Mailing and Restricted Delivery API batch-level `certificate_of_mailing` and `restricted_delivery` are Boolean settings on POST /batches. Each feature requires account enablement; they cannot be combined. Certificate of Mailing supports fc only; Restricted Delivery supports cm and cm-rre only. Recipients using incompatible options are rejected. See address-verification.md for mode selection, results, charges and API request defaults. --- # Affidavits, return envelopes and duplicate copies ## Affidavits Use `mailing_options.affidavit`. Affidavits and return envelopes are now enabled by default on company accounts. All recipients in a batch must use the same affidavit value under the published contract. | Code | Meaning | Billing basis in source | | --- | --- | --- | | `sb` | Signed batch affidavit | Batch | | `sl` | Signed letter affidavit | Mailpiece | | `nb` | Notarized batch affidavit | Batch | | `nl` | Notarized letter affidavit | Mailpiece | Notarized options require operational review. Both return envelopes and affidavits are enabled by default in the current company configuration. An affidavit concerns the mailing described in that document; it is not a carrier-delivery guarantee. ## Return envelopes The public API documents these `return_envelope` values: | Code | Meaning | | --- | --- | | `re-empty` | No return envelope | | `re-9npna` | Blank #9 envelope, without postage or pre-addressing | | `re-9pna` | Postage, without pre-addressing | | `re-9pa` | Postage and pre-addressing | | `re-9pam` | Metered postage and pre-addressing; restricted to documented larger packaging | The source allows the prefix to be omitted on input, but responses include it. Use the complete values in new integrations. The metered variant is documented for `9x12`, `pm` or `pm-box`. International return envelopes are rejected; disabled features may be cleared. Only the listed documented codes are used in integration examples. ## Certified Mail plus a First-Class copy Set recipient `shadow: true` for an eligible `cm` or `cm-rre` piece to request an additional identical First-Class copy. Submit that recipient once; UploadLetters generates the extra copy. The additional copy is printed and billed as another letter. The flag has no effect for other service types and is ignored on check batches. Reconcile the generated additional piece in your records. --- # Business check mailing Use API batch_type check for checks only or letter_and_check to include a document. Check mailing must be enabled and bank_account_uid must identify your registered, verified company bank account. No public bank-registration endpoint is supplied here. Each applicable recipient supplies check_options: bank_account_uid, amount and date, with optional memo, note_1 and note_2. Dates use MM-DD-YYYY, not ISO YYYY-MM-DD, and cannot be in the past. Preserve amounts as decimal strings. The recipient supplies the payee information; do not invent a separate payee input field. Letter-and-check batches need PDF configuration and uploaded documents. Check printing is black and white and single-sided; shadow is ignored. Verify the actual bank, payee, amount, date and mailing details before fulfillment. --- # Address verification: workflow, results and billing ## Verification within API mailing orders Verification runs inline with the mailing. The account's configured rate applies, defaulting to $0.05 per recipient. There is no separate per-file verification fee. The current implementation charges for unsuccessful lookups and shadow First-Class copies. An additional forwarding-address mailing generated by BOTH mode has a normal mailing charge but no additional verification fee for that generated copy. A configured zero verification price currently falls back to $0.05; it does not disable the fee. | Mode | Mailing destination and results | | --- | --- | | NONE | Original address; no verification. | | CASS_NCOA_LOOKUP | Mail to the CASS-standardized address and report forwarding information. | | CASS_NCOA_BEST | Use forwarding information when available, otherwise the best available address. | | CASS_NCOA_BOTH | Mail to the standardized address and an additional forwarding address when available. | Failed verification falls back to the original address. Do not infer a carrier-delivery guarantee from a verified address. ## API control Set `address_verification_type` explicitly on POST /batches and every PATCH recipient-addition request. Omitting it uses the company default, including on PATCH, rather than preserving the batch's original selection. Explicit NONE overrides that default. Invalid or incorrectly cased enum values return 422 without creating the batch. An explicit API address_verification_type works independently of company-level CASS/NCOA enablement. The company setting is used only when the API request omits the field. Verification cannot be combined with international mail. Retrieve available LOOKUP results through GET /batches/{processId}/recipients and its `ncoa_lookup` information. International mailing cannot use address verification. Send `NONE` explicitly for an international API batch. --- # Wallet, charging and manual review API access has no separate API subscription, integration or usage charges. Base mailing rates include applicable postage or FedEx freight; additional pages, color and selected add-ons are extra. ## Fulfillment is asynchronous PUT /batches/{processId}/fulfill returns 200 with "Batch put to queue and will be charged and fulfilled." This acknowledges queue acceptance, not completed payment or mailing. Charging happens in the background. An insufficient-funds failure sends a notification and leaves the API order in Pre-Processing; after adding funds, retry fulfillment on that existing batch. Current /fulfill does not return an insufficient-funds 422; that belonged to deprecated /fulfill-v1. Auto Recharge attempts only one reload per order. The configured reload amount must cover the entire shortage. For a $500 order with $200 in the wallet, the shortage is $300. A $100 reload is insufficient: the order is refused and the card is not charged. Raise the configured reload amount or add funds before retrying the existing order. Failed card payment prevents placement. If a top-up succeeds but the wallet remains short, the funds remain in the wallet. If payment succeeds but production stalls, the team has administrative visibility and can restart fulfillment without charging again. Contact support with the existing batch/order reference rather than creating a replacement mailing. ## Company-enabled manual review No request flag is needed. Request fulfillment first: it returns 422 with "Batch should be reviewed at web portal in incomplete orders." No mailing charge is taken, the order moves to Incomplete Orders as Draft, and a review email is sent. Invalid-letter or missing-PDF errors are returned before the review hold is established. Open the draft in the application to review/edit/delete letters, continue to Order Summary and pay with wallet or card. The draft remains indefinitely if review is never completed. An API batch never submitted for fulfillment stays in Pre-Processing. ## Reconcile transactions GET /batches/transactions supplies wallet information. Balance is decimal dollars; signed transaction amounts are integer cents. Retain the batch ID and your transaction references. Use bounded polling rather than repeatedly fetching an ever-growing transaction history. --- # Statuses, tracking and document records ## Separate three stages Draft preparation, production status and carrier events answer different questions. A queued fulfillment request is not a mailed item. A printed letter is not carrier delivery. Read batch and letter status together with available tracking events. ## Retrieve records `GET /batches/{processId}` reads batch state and preparation counters. `GET /batches/{processId}/letters` returns letter records and available affidavit image links. `GET /batches/{processId}/letters/paged` is preferable for browsing larger batches. The original contract allows `letters` and `affidavit_images` to be null before printing; handle that without treating it as an empty completed mailing. Letter fields include document-image links, available Return Receipt Electronic image links, return-mail images and `tracking_info`, where applicable. Do not require every artifact to exist immediately or for every service. Signed document URLs expire. Retrieve available files promptly and request fresh links when needed; a stored URL is not a permanent document archive. ## Interpret tracking accurately First-Class visibility comes from USPS Intelligent Mail barcode scans. It is not carrier-confirmed delivery. Any estimated or inferred application delivery status must be distinguished from a carrier event. Certified Mail and Priority Mail use their applicable USPS tracking. Return Receipt Electronic is a separate record when available. The `tracking_info` payload can vary by carrier and event source. Preserve the original record and normalize only fields you have validated. Do not generate a universal delivered=true rule from a single example. ## Listing filters are not a universal status enum The `/batches` list filter documents numeric statuses 0 draft, 1 processing, 2 printed, 3 mailed, 4 in transit, 5 delivered, 6 canceled, 10 error and 11 pre-processing. Do not assume that every output status field uses those same integers. Keep batch filters separate from carrier events and retain the returned production status. Mailing documents and associated records are retained for seven years under applicable company policies. That retention statement does not make temporary download URLs permanent. There are no webhooks; use controlled polling. --- # Errors, partial acceptance and safe retries ## Partial acceptance is current behavior HTTP 200 does not mean every recipient was accepted. Inspect invalid_letters and field errors, compare intended and saved recipients, and reconcile missing PDFs. Valid recipients continue when the batch is fulfilled; invalid recipients are excluded and not charged. Verification attempts may still have their separately documented charge. Before fulfillment, send only corrected rejected recipients using PATCH /batches/{processId}/recipients and upload their PDFs. Do not resend accepted recipients. Once fulfillment is requested, recipients cannot be added. ## Duplicate protection differs by operation - POST /batches has no idempotency key: repeating it creates another batch. - PATCH recipients appends recipients: replaying it can duplicate them. - PUT fulfill on the same batch is safe to retry after checking state: an already-requested/already-fulfilled response is 422 and billing refuses to charge an already-paid order again. After an ambiguous create timeout, inspect GET /batches?from=&to= and GET /batches/{processId} before creating anything else. Preserve references and inspect status, in_loading and the returned fulfillment-request indicator. Existing source schemas use async_fullfill_requested, while developer prose also uses async_fulfill_requested; preserve returned fields rather than synthesizing readiness from a missing value. ## HTTP handling 401 indicates authentication failure; 404 indicates missing/inaccessible batch; 422 covers validation, missing documents, already-requested fulfillment and manual-review holds. Read the response body. Insufficient funds on current asynchronous fulfill is a later notification/state outcome, not a synchronous 422. ## Operational bounds Start with about 100 recipients per POST or recipient PATCH as an operational recommendation. The API enforces no fixed recipient-count limit on either request or on the batch. Append additional groups to the same draft before fulfillment. Build around your company’s Single PDF Max Size setting, which defaults to 15 MB per PDF. A setting of 0 means the company-level per-file limit is disabled. The API does not enforce the previously documented 20 MB total request limit. No fixed cumulative API upload or total-page cap is documented. Per-letter envelope capacities still apply. Coordinate unusually large uploads with UploadLetters. There is no sandbox, webhook support or configured API rate limit. All fulfilled batches are real and charged. Poll with bounded backoff and do not run submission examples as automatic tests. --- # Common integration patterns ## One PDF, many destinations Give each recipient the same `pdf_file_config.pdf_name`, its own address and a stable `unique_id`. Upload the PDF once. Reconcile every intended recipient before fulfillment. ## Personalized documents in one PDF Give each recipient the same filename and a different single page or inclusive page range. Verify the range against the actual uploaded PDF. Never infer document boundaries from an example alone. ## Separate PDFs for separate cases Assign a unique filename per case or mailpiece, reference it exactly and upload those files using repeated `letters[]` fields. Choose stable client references that contain no unnecessary sensitive case information. ## Certified Mail and an additional First-Class copy Use `service_type: "cm-rre"` when Return Receipt Electronic is required. Add `shadow: true` only when the additional billable First-Class copy is intended. Applicable affidavit choices are separate options. ## Recurring file-based workflows ## International or FedEx workflows The public service enum includes international options, but the postal-address schema has unresolved international constraints. Obtain an approved destination example before implementing. For the public API-key workflow, use case-sensitive `service_type: "FedEx"` with explicit `envelope_type: "overnight"` or `"2day"` on FedEx-enabled accounts. Keep FedEx recipients in a separate batch from USPS recipients. Supply `return_address.phone` for the sender and `address.phone` for the recipient. A configured account default can supply the recipient phone. --- # Integrate with an AI coding tool ## Supply the right context Give your coding tool `openapi.json`, this guide, the quickstart and CONTRACT-GAPS.md. Use `llms-full.txt` for a single plain-text documentation bundle. These are documentation resources, not a promise of search-engine ranking or an agent runtime. Never paste a real API key, client document or production recipient list into a shared prompt. Configure credentials locally after reviewing generated code. ## Starter prompt ```text Build a server-side UploadLetters integration from the attached curated OpenAPI contract and guides. Use x-api-key authentication and the public /batches flow. Create draft -> upload multipart letters[] -> verify all recipients and background processing -> explicit fulfillment -> retrieve records. Keep fulfillment a separate deliberate operation because it queues wallet charging and mailing. Do not invent endpoints, SDKs, service codes, sandbox behavior, webhooks, idempotency support or undocumented enum values. Reject unknown payload fields locally. Reconcile partial acceptance and every intended recipient. Preserve batch_id for later requests. Implement bounded read polling and a visible unresolved state after ambiguous mutation responses. Never replay a charge or create automatically. Handle null records and expiring artifact URLs. Distinguish First-Class scan visibility from carrier-confirmed delivery. Stop and identify a contract gap when the provided specification conflicts with a required workflow. First show the proposed data flow and payloads. Do not execute production requests. ``` ## Review generated output Check exact field spelling, multipart construction, filename mapping, money units, expected-recipient reconciliation and the explicit fulfillment boundary. A compiling client is not proof that it sends the correct documents to the correct people. ## Modern documentation delivery Publish crawlable HTML with sidebar navigation, search, anchored headings, copyable examples and a download of the versioned OpenAPI file. Provide Markdown views, `llms.txt` and the combined text bundle. Interactive API tools should make production submission unmistakable and never auto-run a fulfillment example. A documentation host's AI features do not add capabilities to the UploadLetters API. --- # Before enabling an integration 1. Keep API keys server-side and use the documented x-api-key interface. 2. Validate recipients, exact PDF filenames, physical-sheet capacity and selected mailing options. 3. Separate USPS/FedEx and domestic/international batches. 4. Handle partial acceptance explicitly and retain customer references locally. 5. Treat fulfillment queue acceptance, payment, production and carrier events as different stages. 6. Use status polling; no sandbox or webhooks are available. 7. Prevent local duplicate submissions and reconcile ambiguous API creation outcomes before resubmission. 8. Keep current behavior separate from future improvements. No proposed reminder/deletion, webhook, sandbox or duplicate-protection feature is promised. Documentation checks do not place orders. Controlled real integration testing is a separate operational step and has not been performed as part of this website update. --- # Advanced: web-application import routes The original specification combines the public mailing API with session-authenticated spreadsheet-import routes. These are kept in `openapi-full-source.json` for completeness, but intentionally excluded from the curated public API-key reference. The import routes cover uploading an import file, extracting headers, validating a mapping, validating rows, reading or editing staged rows, retrieving errors and fulfilling the import. Their authentication is a Bearer web-app session, not the public `x-api-key` workflow. Do not use `/batches/import/fulfill` as the fulfillment call in the public quickstart. Do not attempt an unattended integration using an undocumented login or token-refresh sequence. Session lifecycle, supported external use, schema versioning and feature ownership need confirmation from the development team. The legacy `PUT /batches/{processId}/fulfill-v1` remains in the source archive. New public integrations should use `/fulfill`. The newer operation queues preparation; the legacy route is documented as rejecting batches while preparation is still underway. The full endpoint inventory is supplied in `reference-full.html`, with each authentication requirement visible. These routes should only become public integration guides after their contract and support status are approved.