{
  "manifest_version": "1.0.0",
  "template": {
    "id": "509aabad-7dea-486d-aa97-2b0b8a6c0921",
    "slug": "plunk-or-just-updated-resend-alternative",
    "name": "Plunk | (Just Updated) Resend Alternative Email API On Your AWS SES, Admin And API Keys Ready",
    "description": "Plunk self-hosted email API on AWS SES, dashboard and API keys set",
    "url": "https://railway.com/deploy/plunk-or-just-updated-resend-alternative",
    "upstream": {
      "image": "ghcr.io/useplunk/plunk:0.18.0@sha256:a5c2c691f0d895489e067d971fca404a70dfd19a1380295e3459c3dfe9d86e04"
    }
  },
  "status": "unvalidated",
  "validated_at": null,
  "success_rate_30d": null,
  "services": [
    {
      "name": "plunk-api",
      "source": {
        "image": "ghcr.io/useplunk/plunk:0.18.0@sha256:a5c2c691f0d895489e067d971fca404a70dfd19a1380295e3459c3dfe9d86e04"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "postgres",
      "source": {
        "image": "postgres:17-alpine"
      },
      "needs_volume": true,
      "volume_mount_path": "/var/lib/postgresql",
      "http": false
    },
    {
      "name": "plunk-dashboard",
      "source": {
        "image": "ghcr.io/useplunk/plunk:0.18.0@sha256:a5c2c691f0d895489e067d971fca404a70dfd19a1380295e3459c3dfe9d86e04"
      },
      "needs_volume": false,
      "http": true
    },
    {
      "name": "redis",
      "source": {
        "image": "redis:7-alpine"
      },
      "needs_volume": true,
      "volume_mount_path": "/data",
      "http": false
    }
  ],
  "required_inputs": [
    {
      "key": "API_URI",
      "service": "plunk-api",
      "description": "Provide a value for API_URI.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "REDIS_URL",
      "service": "plunk-api",
      "description": "Provide a value for REDIS_URL.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "JWT_SECRET",
      "service": "plunk-api",
      "description": "Provide a value for JWT_SECRET.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "DATABASE_URL",
      "service": "plunk-api",
      "description": "Provide a value for DATABASE_URL.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_private_domain"
    },
    {
      "key": "DASHBOARD_URI",
      "service": "plunk-api",
      "description": "Provide a value for DASHBOARD_URI.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "PLUNK_PUBLIC_KEY",
      "service": "plunk-api",
      "description": "Provide a value for PLUNK_PUBLIC_KEY.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "PLUNK_SECRET_KEY",
      "service": "plunk-api",
      "description": "Provide a value for PLUNK_SECRET_KEY.",
      "secret": true,
      "strategy": "generate",
      "generate": "random_base64_32"
    },
    {
      "key": "PLUNK_ADMIN_EMAIL",
      "service": "plunk-api",
      "description": "Provide a value for PLUNK_ADMIN_EMAIL.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "PLUNK_ADMIN_PASSWORD",
      "service": "plunk-api",
      "description": "Provide a value for PLUNK_ADMIN_PASSWORD.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "POSTGRES_PASSWORD",
      "service": "postgres",
      "description": "Provide a value for POSTGRES_PASSWORD.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    },
    {
      "key": "API_URI",
      "service": "plunk-dashboard",
      "description": "Provide a value for API_URI.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "reference_variable"
    },
    {
      "key": "DASHBOARD_URI",
      "service": "plunk-dashboard",
      "description": "Provide a value for DASHBOARD_URI.",
      "secret": false,
      "strategy": "railway_provided",
      "railway_source": "railway_domain"
    },
    {
      "key": "REDIS_PASSWORD",
      "service": "redis",
      "description": "Provide a value for REDIS_PASSWORD.",
      "secret": true,
      "strategy": "generate",
      "generate": "strong_password"
    }
  ],
  "deploy": {
    "mcp": {
      "server": "railway",
      "tool": "deploy_template",
      "args": {
        "template_code": "plunk-or-just-updated-resend-alternative"
      }
    },
    "cli": "railway deploy --template plunk-or-just-updated-resend-alternative",
    "api": {
      "method": "POST",
      "path": "/graphql/v2",
      "body": {
        "query": "mutation templateDeploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }",
        "variables": {
          "input": {
            "templateId": "509aabad-7dea-486d-aa97-2b0b8a6c0921",
            "serializedConfig": {
              "buckets": {},
              "services": {
                "b8533c02-eceb-493e-85e3-b3454960b659": {
                  "icon": null,
                  "name": "plunk-api",
                  "deploy": {
                    "startCommand": "/bin/sh -c 'echo IyEvYmluL3NoCiMgUmFpbHdheSBib290IGZvciB0aGUgUGx1bmsgQVBJIHNlcnZpY2UgKEFQSSArIHF1ZXVlIHdvcmtlciBpbiBvbmUgY29udGFpbmVyKS4KIwojIFVwc3RyZWFtJ3MgYWxsLWluLW9uZSBpbWFnZSBmcm9udHMgZm91ciBhcHBzIHdpdGggbmdpbnggb24gZm91ciBob3N0bmFtZXMsIHdoaWNoCiMgUmFpbHdheSBjYW5ub3QgZ2l2ZSBvbmUgc2VydmljZS4gVGhpcyBydW5zIHRoZSBBUEkgKGFuZCBpdHMgd29ya2VyKSBkaXJlY3RseSwKIyBzbyB0aGUgZGFzaGJvYXJkIGlzIGEgc2VwYXJhdGUgc2VydmljZSB3aXRoIGl0cyBvd24gZG9tYWluLgpzZXQgLWV1CgojIFNldHRpbmdzIGEgdGVtcGxhdGUgdmFyaWFibGUgY2Fubm90IGNhcnJ5ICh0ZW1wbGF0ZUdlbmVyYXRlIGRyb3BzIGxpdGVyYWxzKS4KZXhwb3J0IE5PREVfRU5WPXByb2R1Y3Rpb24KZXhwb3J0IExBTkRJTkdfVVJJPSIke0xBTkRJTkdfVVJJOi1odHRwczovL3d3dy51c2VwbHVuay5jb219IgpleHBvcnQgV0lLSV9VUkk9IiR7V0lLSV9VUkk6LWh0dHBzOi8vZG9jcy51c2VwbHVuay5jb219IgpleHBvcnQgQVdTX1NFU19SRUdJT049IiR7QVdTX1NFU19SRUdJT046LXVzLWVhc3QtMX0iCiMgVGhlIEFQSSByZWZ1c2VzIHRvIGJvb3Qgd2l0aG91dCBTRVMgY3JlZGVudGlhbHMuIFRoZXNlIHBsYWNlaG9sZGVycyBsZXQgaXQgc3RhcnQ7CiMgc2VuZGluZyBuZWVkcyB0aGUgZGVwbG95ZXIncyByZWFsIHZhbHVlcyBzZXQgb24gdGhpcyBzZXJ2aWNlLgpleHBvcnQgQVdTX1NFU19BQ0NFU1NfS0VZX0lEPSIke0FXU19TRVNfQUNDRVNTX0tFWV9JRDotbm90LWNvbmZpZ3VyZWR9IgpleHBvcnQgQVdTX1NFU19TRUNSRVRfQUNDRVNTX0tFWT0iJHtBV1NfU0VTX1NFQ1JFVF9BQ0NFU1NfS0VZOi1ub3QtY29uZmlndXJlZH0iCiMgVGhlIGFkbWluIGFjY291bnQgYmVsb3cgaXMgY3JlYXRlZCBhdCBib290LCBzbyBwdWJsaWMgc2lnbnVwIHN0YXlzIGNsb3NlZC4KZXhwb3J0IERJU0FCTEVfU0lHTlVQUz0iJHtESVNBQkxFX1NJR05VUFM6LXRydWV9IgpleHBvcnQgRElSRUNUX0RBVEFCQVNFX1VSTD0iJERBVEFCQVNFX1VSTCIKCmVjaG8gIltyYWlsd2F5XSBwbHVuayBhcGkgdWlkPSQoaWQgLXUpIHBvcnQ9JHtQT1JUOi11bnNldH0gYXBpX3VyaT0kQVBJX1VSSSBkYXNoYm9hcmRfdXJpPSREQVNIQk9BUkRfVVJJIgoKY2QgL2FwcAp1bnRpbCAvYXBwL25vZGVfbW9kdWxlcy8uYmluL3ByaXNtYSBtaWdyYXRlIGRlcGxveSAtLXNjaGVtYT0vYXBwL3BhY2thZ2VzL2RiL3ByaXNtYS9zY2hlbWEucHJpc21hOyBkbwogIGVjaG8gIltyYWlsd2F5XSBtaWdyYXRlIGZhaWxlZCwgcmV0cnlpbmcgaW4gM3MiCiAgc2xlZXAgMwpkb25lCgpjZCAvYXBwL2FwcHMvYXBpCm5vZGUgLWUgJwpjb25zdCB7IFByaXNtYUNsaWVudCB9ID0gcmVxdWlyZSgiQHByaXNtYS9jbGllbnQiKTsKY29uc3QgYmNyeXB0ID0gcmVxdWlyZSgiYmNyeXB0Iik7CmNvbnN0IHByaXNtYSA9IG5ldyBQcmlzbWFDbGllbnQoKTsKKGFzeW5jICgpID0+IHsKICBjb25zdCBlbWFpbCA9IHByb2Nlc3MuZW52LlBMVU5LX0FETUlOX0VNQUlMLnRyaW0oKS50b0xvd2VyQ2FzZSgpOwogIGNvbnN0IGhhc2ggPSBhd2FpdCBiY3J5cHQuaGFzaChwcm9jZXNzLmVudi5QTFVOS19BRE1JTl9QQVNTV09SRCwgMTApOwogIGNvbnN0IHVzZXIgPSBhd2FpdCBwcmlzbWEudXNlci51cHNlcnQoewogICAgd2hlcmU6IHsgZW1haWwgfSwKICAgIHVwZGF0ZTogeyBwYXNzd29yZDogaGFzaCwgdHlwZTogIlBBU1NXT1JEIiwgZW1haWxWZXJpZmllZDogdHJ1ZSB9LAogICAgY3JlYXRlOiB7IGVtYWlsLCBwYXNzd29yZDogaGFzaCwgdHlwZTogIlBBU1NXT1JEIiwgZW1haWxWZXJpZmllZDogdHJ1ZSB9LAogIH0pOwogIGxldCBwcm9qZWN0ID0gYXdhaXQgcHJpc21hLnByb2plY3QuZmluZEZpcnN0KHsgd2hlcmU6IHsgbmFtZTogIkRlZmF1bHQiLCBtZW1iZXJzOiB7IHNvbWU6IHsgdXNlcklkOiB1c2VyLmlkIH0gfSB9IH0pOwogIGNvbnN0IGtleXMgPSB7IHB1YmxpYzogcHJvY2Vzcy5lbnYuUExVTktfUFVCTElDX0tFWSwgc2VjcmV0OiBwcm9jZXNzLmVudi5QTFVOS19TRUNSRVRfS0VZIH07CiAgaWYgKCFwcm9qZWN0KSB7CiAgICBwcm9qZWN0ID0gYXdhaXQgcHJpc21hLnByb2plY3QuY3JlYXRlKHsKICAgICAgZGF0YTogeyBuYW1lOiAiRGVmYXVsdCIsIC4uLmtleXMsIG1lbWJlcnM6IHsgY3JlYXRlOiB7IHVzZXJJZDogdXNlci5pZCwgcm9sZTogIk9XTkVSIiB9IH0gfSwKICAgIH0pOwogICAgY29uc29sZS5sb2coIltyYWlsd2F5XSBjcmVhdGVkIGFkbWluIiwgZW1haWwsICJhbmQgcHJvamVjdCIsIHByb2plY3QuaWQpOwogIH0gZWxzZSB7CiAgICBwcm9qZWN0ID0gYXdhaXQgcHJpc21hLnByb2plY3QudXBkYXRlKHsgd2hlcmU6IHsgaWQ6IHByb2plY3QuaWQgfSwgZGF0YToga2V5cyB9KTsKICAgIGNvbnNvbGUubG9nKCJbcmFpbHdheV0gYWRtaW4iLCBlbWFpbCwgInByb2plY3QiLCBwcm9qZWN0LmlkLCAia2V5cyByZS1hcHBsaWVkIik7CiAgfQogIGF3YWl0IHByaXNtYS4kZGlzY29ubmVjdCgpOwp9KSgpLmNhdGNoKChlKSA9PiB7IGNvbnNvbGUuZXJyb3IoIltyYWlsd2F5XSBib290c3RyYXAgZmFpbGVkIiwgZSk7IHByb2Nlc3MuZXhpdCgxKTsgfSk7CicKCiMgUXVldWUgd29ya2VyOiByZXN0YXJ0IGl0IGlmIGl0IGRpZXMsIHRoZSBBUEkga2VlcHMgc2VydmluZyBlaXRoZXIgd2F5LgooCiAgY2QgL2FwcAogIHdoaWxlIHRydWU7IGRvCiAgICBub2RlIC9hcHAvYXBwcy9hcGkvZGlzdC9qb2JzL3dvcmtlci5qcyB8fCB0cnVlCiAgICBlY2hvICJbcmFpbHdheV0gd29ya2VyIGV4aXRlZCwgcmVzdGFydGluZyBpbiAycyIKICAgIHNsZWVwIDIKICBkb25lCikgJgoKY2QgL2FwcApleGVjIG5vZGUgL2FwcC9hcHBzL2FwaS9kaXN0L2FwcC5qcwo= | base64 -d > /tmp/boot.sh; exec /bin/sh /tmp/boot.sh'",
                    "healthcheckPath": "/health",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/useplunk/plunk:0.18.0@sha256:a5c2c691f0d895489e067d971fca404a70dfd19a1380295e3459c3dfe9d86e04"
                  },
                  "variables": {
                    "API_URI": {
                      "isOptional": false,
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "REDIS_URL": {
                      "isOptional": false,
                      "defaultValue": "redis://default:${{redis.REDIS_PASSWORD}}@${{redis.RAILWAY_PRIVATE_DOMAIN}}:6379"
                    },
                    "JWT_SECRET": {
                      "isOptional": false,
                      "defaultValue": "{{JWT_SECRET}}"
                    },
                    "DATABASE_URL": {
                      "isOptional": false,
                      "defaultValue": "postgresql://postgres:${{postgres.POSTGRES_PASSWORD}}@${{postgres.RAILWAY_PRIVATE_DOMAIN}}:5432/postgres"
                    },
                    "DASHBOARD_URI": {
                      "isOptional": false,
                      "defaultValue": "https://${{RAILWAY_SERVICE_PLUNK_DASHBOARD_URL}}"
                    },
                    "PLUNK_PUBLIC_KEY": {
                      "isOptional": false,
                      "defaultValue": "{{PLUNK_PUBLIC_KEY}}"
                    },
                    "PLUNK_SECRET_KEY": {
                      "isOptional": false,
                      "defaultValue": "{{PLUNK_SECRET_KEY}}"
                    },
                    "PLUNK_ADMIN_EMAIL": {
                      "isOptional": false,
                      "defaultValue": "admin@${{RAILWAY_PUBLIC_DOMAIN}}"
                    },
                    "PLUNK_ADMIN_PASSWORD": {
                      "isOptional": false,
                      "defaultValue": "{{PLUNK_ADMIN_PASSWORD}}"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:8080": {
                        "port": 8080
                      }
                    }
                  }
                },
                "bbe2440b-2a86-49d3-bed7-f523bfc5dd4f": {
                  "icon": null,
                  "name": "postgres",
                  "deploy": {
                    "startCommand": null,
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "postgres:17-alpine"
                  },
                  "variables": {
                    "POSTGRES_PASSWORD": {
                      "isOptional": false,
                      "defaultValue": "{{POSTGRES_PASSWORD}}"
                    }
                  },
                  "volumeMounts": {
                    "bbe2440b-2a86-49d3-bed7-f523bfc5dd4f": {
                      "mountPath": "/var/lib/postgresql"
                    }
                  }
                },
                "c2f962a1-f038-4267-be92-984ef2f312ee": {
                  "icon": null,
                  "name": "plunk-dashboard",
                  "deploy": {
                    "startCommand": "/bin/sh -c 'echo IyEvYmluL3NoCiMgUmFpbHdheSBib290IGZvciB0aGUgUGx1bmsgZGFzaGJvYXJkIChOZXh0LmpzIHN0YW5kYWxvbmUgYnVpbGQpLgojCiMgVGhlIGJ1aWxkIGJha2VzIHBsYWNlaG9sZGVyIFVSTHMgaW50byB0aGUgYnVuZGxlOyB1cHN0cmVhbSdzIG93biBzY3JpcHQgcmV3cml0ZXMKIyB0aGVtIGZyb20gQVBJX1VSSSAvIERBU0hCT0FSRF9VUkkgYXQgc3RhcnQuIFJ1biBpdCwgdGhlbiBzdGFydCB0aGUgc2VydmVyIGRpcmVjdGx5LgpzZXQgLWUKCmV4cG9ydCBOT0RFX0VOVj1wcm9kdWN0aW9uCmV4cG9ydCBMQU5ESU5HX1VSST0iJHtMQU5ESU5HX1VSSTotaHR0cHM6Ly93d3cudXNlcGx1bmsuY29tfSIKZXhwb3J0IFdJS0lfVVJJPSIke1dJS0lfVVJJOi1odHRwczovL2RvY3MudXNlcGx1bmsuY29tfSIKZXhwb3J0IEhPU1ROQU1FPTAuMC4wLjAKCmVjaG8gIltyYWlsd2F5XSBwbHVuayBkYXNoYm9hcmQgdWlkPSQoaWQgLXUpIHBvcnQ9JHtQT1JUOi11bnNldH0gYXBpX3VyaT0kQVBJX1VSSSBkYXNoYm9hcmRfdXJpPSREQVNIQk9BUkRfVVJJIgoKLiAvYXBwL2RvY2tlci9yZXBsYWNlLXVybHMtb3B0aW1pemVkLnNoCnJlcGxhY2VfdXJsc19pbl9hcHAgIndlYiIgIi9hcHAvYXBwcy93ZWIvLm5leHQvc3RhbmRhbG9uZS9hcHBzL3dlYiIKCmNkIC9hcHAvYXBwcy93ZWIvLm5leHQvc3RhbmRhbG9uZQpleGVjIG5vZGUgYXBwcy93ZWIvc2VydmVyLmpzCg== | base64 -d > /tmp/boot.sh; exec /bin/sh /tmp/boot.sh'",
                    "healthcheckPath": "/auth/login",
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "ghcr.io/useplunk/plunk:0.18.0@sha256:a5c2c691f0d895489e067d971fca404a70dfd19a1380295e3459c3dfe9d86e04"
                  },
                  "variables": {
                    "API_URI": {
                      "isOptional": false,
                      "defaultValue": "https://${{RAILWAY_SERVICE_PLUNK_API_URL}}"
                    },
                    "DASHBOARD_URI": {
                      "isOptional": false,
                      "defaultValue": "https://${{RAILWAY_PUBLIC_DOMAIN}}"
                    }
                  },
                  "networking": {
                    "serviceDomains": {
                      "<hasDomain>:8080": {
                        "port": 8080
                      }
                    }
                  }
                },
                "d87215e1-59ff-4027-ba8d-0ba322a6457c": {
                  "icon": null,
                  "name": "redis",
                  "deploy": {
                    "startCommand": "/bin/sh -c 'chown -R redis:redis /data && exec docker-entrypoint.sh redis-server --requirepass \"$REDIS_PASSWORD\" --appendonly yes --dir /data'",
                    "healthcheckPath": null,
                    "restartPolicyType": "ON_FAILURE",
                    "restartPolicyMaxRetries": 10
                  },
                  "source": {
                    "image": "redis:7-alpine"
                  },
                  "variables": {
                    "REDIS_PASSWORD": {
                      "isOptional": false,
                      "defaultValue": "{{REDIS_PASSWORD}}"
                    }
                  },
                  "volumeMounts": {
                    "d87215e1-59ff-4027-ba8d-0ba322a6457c": {
                      "mountPath": "/data"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "post_deploy": {
    "healthcheck": {
      "service": "plunk-api",
      "method": "GET",
      "path": "/health",
      "expect_status": 200
    }
  },
  "resources": {
    "expected_services": 4,
    "needs_volume": true
  },
  "generated_at": "2026-11-01T16:15:09.105Z",
  "generator_version": "0.1.0"
}
