{
  "info": {
    "name": "Mail A Letter API",
    "description": "Send physical mail with an HTTP request.\n\nSetup:\n1. On mailaletter.com, open Account → set 'Enable API' to Yes → Save. Copy your keys.\n2. Set the `api_key` collection variable. Use your sandbox key (mal_test_...) while integrating - test mode runs full validation and real pricing but stores, charges, and mails nothing.\n3. Run 'Submit letter' - it saves the returned id into `letter_id` for the status request.\n\nBilling is prepaid from your MailBank; there is no card payment through the API. Limits: PDF only, 20MB, US Letter/A4, 120 requests/min.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [ { "key": "token", "value": "{{api_key}}", "type": "string" } ]
  },
  "variable": [
    { "key": "base_url", "value": "https://www.mailaletter.com/api/v1" },
    { "key": "api_key", "value": "mal_test_REPLACE_WITH_YOUR_SANDBOX_KEY" },
    { "key": "letter_id", "value": "" },
    { "key": "sample_pdf_base64", "value": "JVBERi0xLjQKJeLjz9MKMiAwIG9iago8PC9MZW5ndGggMTYwL0ZpbHRlci9GbGF0ZURlY29kZT4+c3RyZWFtCnicVY5BDoIwEEX3PcVf4qIIGNGtJrjShUk9ANhB0Eq1HSTc3sJKk0n+LN6b+W+xV2KVY7POobRIINPttCwPKdIMqhaRalqPMGWHIivA5BmGmMlB22v/pI5jXF7Glpo0qhGnsjW740zEwVBB8GCLD7m2HsENoZ9xyVZWxlZyoe7hdfLXIPJsXXkj1MYOGKx7eFCnp0Mh4h+lUOIsvoOSPLkKZW5kc3RyZWFtCmVuZG9iago0IDAgb2JqCjw8L1R5cGUvUGFnZS9NZWRpYUJveFswIDAgNjEyIDc5Ml0vUmVzb3VyY2VzPDwvRm9udDw8L0YxIDEgMCBSPj4+Pi9Db250ZW50cyAyIDAgUi9QYXJlbnQgMyAwIFI+PgplbmRvYmoKMSAwIG9iago8PC9UeXBlL0ZvbnQvU3VidHlwZS9UeXBlMS9CYXNlRm9udC9IZWx2ZXRpY2EvRW5jb2RpbmcvV2luQW5zaUVuY29kaW5nPj4KZW5kb2JqCjMgMCBvYmoKPDwvVHlwZS9QYWdlcy9Db3VudCAxL0tpZHNbNCAwIFJdPj4KZW5kb2JqCjUgMCBvYmoKPDwvVHlwZS9DYXRhbG9nL1BhZ2VzIDMgMCBSPj4KZW5kb2JqCjYgMCBvYmoKPDwvUHJvZHVjZXIoaVRleHRTaGFycJIgNS41LjEzLjQgqTIwMDAtMjAyNCBpVGV4dCBHcm91cCBOViBcKEFHUEwtdmVyc2lvblwpKS9DcmVhdGlvbkRhdGUoRDoyMDI2MDcxNDExMzU0OC0wNycwMCcpL01vZERhdGUoRDoyMDI2MDcxNDExMzU0OC0wNycwMCcpPj4KZW5kb2JqCnhyZWYKMCA3CjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDM1NCAwMDAwMCBuIAowMDAwMDAwMDE1IDAwMDAwIG4gCjAwMDAwMDA0NDIgMDAwMDAgbiAKMDAwMDAwMDI0MiAwMDAwMCBuIAowMDAwMDAwNDkzIDAwMDAwIG4gCjAwMDAwMDA1MzggMDAwMDAgbiAKdHJhaWxlcgo8PC9TaXplIDcvUm9vdCA1IDAgUi9JbmZvIDYgMCBSL0lEIFs8OGU5N2MyYzFlYWIyMTBhYzQzODQxYWNkOTc3MDMxYjg+PDhlOTdjMmMxZWFiMjEwYWM0Mzg0MWFjZDk3NzAzMWI4Pl0+PgolaVRleHQtNS41LjEzLjQKc3RhcnR4cmVmCjcwMwolJUVPRgo=" }
  ],
  "item": [
    {
      "name": "Get MailBank balance",
      "request": {
        "method": "GET",
        "url": { "raw": "{{base_url}}/balance", "host": ["{{base_url}}"], "path": ["balance"] },
        "description": "Your prepaid balance. Every letter draws from this."
      }
    },
    {
      "name": "Submit letter",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (pm.response.code === 201) {",
              "    pm.collectionVariables.set('letter_id', pm.response.json().id);",
              "    console.log('letter_id set to ' + pm.response.json().id);",
              "}",
              "pm.test('201 created', () => pm.response.to.have.status(201));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" } ],
        "url": { "raw": "{{base_url}}/letters", "host": ["{{base_url}}"], "path": ["letters"] },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"file_name\": \"sample-letter.pdf\",\n  \"file\": \"{{sample_pdf_base64}}\",\n  \"recipient\": {\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Doe\",\n    \"company\": \"Acme Corp\",\n    \"address1\": \"500 Union St\",\n    \"address2\": \"Suite 100\",\n    \"city\": \"Seattle\",\n    \"state\": \"WA\",\n    \"postal_code\": \"98101\",\n    \"country\": \"US\"\n  },\n  \"options\": {\n    \"return_envelope\": false,\n    \"delivery_service\": \"first_class\"\n  }\n}"
        },
        "description": "Submits a 1-page sample PDF. With a mal_test_ key nothing is stored, charged, or mailed; with a mal_live_ key this charges your MailBank and mails for real. Saves the returned id into {{letter_id}}."
      }
    },
    {
      "name": "Get letter status",
      "request": {
        "method": "GET",
        "url": { "raw": "{{base_url}}/letters/{{letter_id}}", "host": ["{{base_url}}"], "path": ["letters", "{{letter_id}}"] },
        "description": "Run 'Submit letter' first to populate {{letter_id}}. Test-mode letters progress automatically: processing → printing (after 5 min) → mailed (after 30 min)."
      }
    },
    {
      "name": "Trigger: insufficient funds (sandbox)",
      "request": {
        "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" } ],
        "url": { "raw": "{{base_url}}/letters", "host": ["{{base_url}}"], "path": ["letters"] },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"file_name\": \"sample-letter.pdf\",\n  \"file\": \"{{sample_pdf_base64}}\",\n  \"recipient\": {\n    \"first_name\": \"TEST-INSUFFICIENT-FUNDS\",\n    \"last_name\": \"\",\n    \"company\": \"\",\n    \"address1\": \"500 Union St\",\n    \"address2\": \"\",\n    \"city\": \"Seattle\",\n    \"state\": \"WA\",\n    \"postal_code\": \"98101\",\n    \"country\": \"US\"\n  },\n  \"options\": {\n    \"return_envelope\": false,\n    \"delivery_service\": \"first_class\"\n  }\n}"
        },
        "description": "Sandbox-only magic trigger: recipient first_name TEST-INSUFFICIENT-FUNDS always returns 402 with the insufficient_funds error shape, so you can build your top-up handling without draining a real balance. All body fields are shown; company, address2, and options are optional."
      }
    },
    {
      "name": "Trigger: invalid address (sandbox)",
      "request": {
        "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" } ],
        "url": { "raw": "{{base_url}}/letters", "host": ["{{base_url}}"], "path": ["letters"] },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"file_name\": \"sample-letter.pdf\",\n  \"file\": \"{{sample_pdf_base64}}\",\n  \"recipient\": {\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Doe\",\n    \"company\": \"\",\n    \"address1\": \"500 Union St\",\n    \"address2\": \"\",\n    \"city\": \"Seattle\",\n    \"state\": \"WA\",\n    \"postal_code\": \"00000\",\n    \"country\": \"US\"\n  },\n  \"options\": {\n    \"return_envelope\": false,\n    \"delivery_service\": \"first_class\"\n  }\n}"
        },
        "description": "Sandbox-only magic trigger: postal_code 00000 always returns 400 invalid_address."
      }
    },
    {
      "name": "Error: missing API key",
      "request": {
        "auth": { "type": "noauth" },
        "method": "GET",
        "url": { "raw": "{{base_url}}/balance", "host": ["{{base_url}}"], "path": ["balance"] },
        "description": "Expect 401 with {\"error\":{\"code\":\"unauthorized\",...}}."
      }
    },
    {
      "name": "Error: non-PDF upload",
      "request": {
        "method": "POST",
        "header": [ { "key": "Content-Type", "value": "application/json" } ],
        "url": { "raw": "{{base_url}}/letters", "host": ["{{base_url}}"], "path": ["letters"] },
        "body": {
          "mode": "raw",
          "raw": "{\n  \"file_name\": \"letter.docx\",\n  \"file\": \"{{sample_pdf_base64}}\",\n  \"recipient\": {\n    \"first_name\": \"Jane\",\n    \"last_name\": \"Doe\",\n    \"company\": \"\",\n    \"address1\": \"500 Union St\",\n    \"address2\": \"\",\n    \"city\": \"Seattle\",\n    \"state\": \"WA\",\n    \"postal_code\": \"98101\",\n    \"country\": \"US\"\n  },\n  \"options\": {\n    \"return_envelope\": false,\n    \"delivery_service\": \"first_class\"\n  }\n}"
        },
        "description": "Expect 415 unsupported_media_type - the API is PDF-only."
      }
    }
  ]
}
