Sendvelo

Docs

Configuration guide

Set the few required deployment values first, then configure only the channels and storage features your installation uses.

Go-live checklist

  1. Copy .env.example to .env and replace every placeholder secret.
  2. Set public HTTPS URLs, your production license domain, and the license values delivered with your purchase.
  3. Give the backend an AWS identity, preferably an instance or task role instead of long-lived access keys.
  4. Configure platform email before inviting users or using password reset. Add push and media only if you need them.
  5. Start Sendvelo, activate the license, then test each enabled provider from an organization you own.

Core URLs and secrets

FRONTEND_APP_URL is the public UI origin. API_PUBLIC_URL is the public API origin used by webhooks and tracking. NEXT_PUBLIC_API_BASE_URL is baked into the compiled frontend image and must point to that same API.

Generate separate, random values for JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, JWT_PASSWORD_RESET_SECRET, and EMAIL_TRACKING_SECRET. Do not reuse passwords or commit the filled .env.

openssl rand -base64 48

License configuration

The purchase email, secure confirmation page, account page, and downloaded release provide LICENSE_SERVER_URL and LICENSE_PUBLIC_KEY. Copy them exactly; only the domain is customer-specific.

DEPLOYMENT_MODE=self_hosted
LICENSE_SERVER_URL=https://licenses.example.com
LICENSE_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"
LICENSE_DOMAIN=app.example.com
LICENSE_VALIDATION_INTERVAL=48h
LICENSE_GRACE_PERIOD=7d
  • DEPLOYMENT_MODE=self_hosted is mandatory in customer builds. saas is reserved for Sendvelo's vendor-operated cloud service; customer images reject it.
  • LICENSE_SERVER_URL is the public HTTPS API used by the backend for activation, periodic validation, and deactivation. The browser does not call it.
  • LICENSE_PUBLIC_KEY verifies signed licenses locally, detects tampering, and permits cached verification during a temporary server outage. It is public; a private signing key must never be present.
  • LICENSE_DOMAIN is your production hostname only, such as app.example.com—no protocol, path, or browser headers.
  • The validation interval and grace period already default to 48h and 7d. Leave them unchanged unless support asks you to adjust them. Shorter validation detects revocation sooner; a longer grace period tolerates outages longer but delays enforcement while offline.

AWS identity and region

AWS_REGION selects the region containing your Secrets Manager secrets and media bucket. Use one region where possible to reduce configuration mistakes.

On EC2, ECS, EKS, or another AWS compute service, attach an IAM role and leave AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY empty. Elsewhere, create a least-privilege IAM user under AWS IAM → Users → Create user, create an access key for an application running outside AWS, and place the two values only in the backend environment.

Scope permissions to your own secret prefix and bucket. Replace the uppercase placeholders below; add kms:Decrypt only when your secrets use a customer-managed KMS key.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:CreateSecret",
        "secretsmanager:PutSecretValue"
      ],
      "Resource": "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:sendvelo/*"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::YOUR_MEDIA_BUCKET/*"
    }
  ]
}

Platform email

Platform email sends password resets, invitations, and other system messages. It is separate from each organization's campaign email provider.

  • EMAIL_PROVIDER_ID: use nodemailer-smtp for an SMTP service or aws-ses for Amazon SES.
  • EMAIL_SECRET_MANAGER_KEY: the AWS Secrets Manager secret name or ARN—not the JSON value or SMTP password.

For SMTP, obtain the host, port, username, and password from your mail provider. Create an AWS Secrets Manager “Other type of secret” using this JSON:

{
  "host": "smtp.example.com",
  "port": 587,
  "secure": false,
  "auth": {
    "user": "smtp-user",
    "pass": "smtp-password"
  },
  "from": "no-reply@example.com"
}

For SES, verify the sender/domain, configure DKIM, and request production access in the SES console. When the backend already uses an IAM role, the secret needs only:

{
  "region": "us-west-1",
  "from": "no-reply@example.com"
}

If SES uses separate credentials, add both accessKeyId and secretAccessKey to the secret. Never provide only one.

Platform push notifications

Set PUSH_PROVIDER_ID=firebase. Create a Firebase project, enable Cloud Messaging, then open Project settings → Service accounts → Generate new private key. Store these three fields from the downloaded service-account JSON in AWS Secrets Manager:

{
  "projectId": "your-firebase-project",
  "clientEmail": "firebase-adminsdk-...@your-project.iam.gserviceaccount.com",
  "privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
}

Set PUSH_SECRET_MANAGER_KEY to that secret's name or ARN. The private key remains server-side. Browser push subscription also needs the matching Firebase web-app configuration baked into the frontend image; use the values supplied for your release or contact support before rebuilding.

Organization channels: email, SMS, push, WhatsApp

Campaign and journey credentials are configured after sign-in under the organization's provider settings. Sendvelo stores them in Secrets Manager under an installation-generated sendvelo/.../tenants/... path.

There is intentionally no SMS_* environment variable. Choose Arkesel in the UI and provide its API key, approved sender ID, and optional callback URL. WhatsApp uses Meta WhatsApp Cloud with an access token, phone-number ID, business-account ID, app secret, and webhook verify token. Tenant email and Firebase push use the same credential shapes shown above.

Obtain SMS credentials from the Arkesel dashboard and WhatsApp credentials from Meta for Developers after creating a business app and adding the WhatsApp product. Provider credentials never belong in browser storage.

Media storage and CDN

MEDIA_S3_BUCKET is the private S3 bucket used for media uploads. Create it in the same AWS region, keep Block Public Access enabled, and grant the backend object read/write/delete permissions.

MEDIA_CDN_BASE_URL is the public HTTPS base used to build final media URLs, without a trailing slash. Prefer CloudFront with Origin Access Control in front of the private bucket; use its domain or your custom CDN domain, such as https://media.example.com. Configure bucket CORS to allow browser PUT, GET, and HEAD from your frontend origin.

Verify before sending

  • The License page reports active, the expected domain, and a recent validation time.
  • Password reset and an organization invitation email arrive.
  • Upload a small image and confirm its CDN URL loads over HTTPS.
  • Send one test message through every organization channel you enabled; do not start with a full campaign.

Continue with the installation guide or return to the documentation overview.