Obtaining API Keys
Step-by-step instructions for getting real credentials for every external provider Closegram integrates with. See Environment Setup for which .env variable each value goes into.
Providers are ordered roughly by how likely you are to need them for local development.
Database & Redis
No account needed — see Local infrastructure via Docker. Only set up a managed Postgres/Redis provider (e.g. Railway, RDS, ElastiCache) when deploying.
LiveKit
Local development: no account needed — the Docker Compose stack runs a real LiveKit server with a hardcoded dev key (devkey / dev1234567890abcdef1234567890abcdef). Point LIVEKIT_URL at ws://localhost:7880 and use those credentials.
Production: either self-host (deploy the same livekit/livekit-server image somewhere reachable, generate your own keypair with livekit-server generate-keys) or use LiveKit Cloud:
- Sign up at cloud.livekit.io and create a project.
- Go to Settings → Keys, create a new API key/secret pair.
- Copy the WebSocket URL, API Key, and API Secret into
LIVEKIT_URL/LIVEKIT_API_KEY/LIVEKIT_API_SECRET.
Firebase
Used for: Google Sign-In token verification (backend), push notifications (backend + iOS + web), and Firebase Auth on the frontend/iOS clients.
- Go to the Firebase console and create a project (or use an existing one).
- Backend service account (fills the
FIREBASE_*backend variables): Project settings (gear icon) → Service accounts → Generate new private key. This downloads a JSON file — map its fields directly toFIREBASE_PROJECT_ID,FIREBASE_PRIVATE_KEY_ID,FIREBASE_PRIVATE_KEY,FIREBASE_CLIENT_EMAIL,FIREBASE_CLIENT_ID,FIREBASE_AUTH_URI,FIREBASE_TOKEN_URI,FIREBASE_AUTH_PROVIDER_CERT_URL,FIREBASE_CLIENT_CERT_URL. When pastingFIREBASE_PRIVATE_KEYinto a.envfile, keep it as a single line with literal\nsequences (matching the format already in.env.example). - Web app config (fills the
NEXT_PUBLIC_FIREBASE_*frontend variables): Project settings → General → scroll to Your apps → add a Web app (</>icon) if one doesn't exist → copy thefirebaseConfigobject'sapiKey,authDomain,projectId,storageBucket,messagingSenderId,appId. - iOS app config (fills
GoogleService-Info.plist): Project settings → General → Your apps → add an iOS app with the bundle ID fromapp.xcodeproj→ downloadGoogleService-Info.plistand replaceapps/ios/app/app/GoogleService-Info.plist. - Enable the sign-in methods you need under Authentication → Sign-in method (Google, and Phone if you want Firebase-based phone auth in addition to the Twilio/SMS path).
- If using push notifications, also enable Cloud Messaging under Project settings — no extra key needed beyond the service account above.
Google Sign-In (OAuth Client)
Separate from the Firebase project above — this is a raw Google Cloud OAuth client, used by two different code paths in the backend (GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET for one strategy, CLIENT_ID/CLIENT_ID_SECRET/REDIRECT_URIs for another).
- Go to Google Cloud Console → select the same project as your Firebase project (Firebase projects are GCP projects under the hood) or create a new one.
- APIs & Services → OAuth consent screen — configure it (External, add your app name/support email) if not already done.
- APIs & Services → Credentials → Create Credentials → OAuth client ID.
- Application type Web application. Add your redirect URI(s) (e.g.
http://localhost:8000/auth/google/callbackfor local dev) — this value also goes intoREDIRECT_URIs. - Copy the generated Client ID and Client Secret — use the same pair for both
GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRETandCLIENT_ID/CLIENT_ID_SECRETunless you specifically want them to be different apps.
Apple Sign-In
Requires a paid Apple Developer account ($99/yr).
- Apple Developer → Certificates, Identifiers & Profiles → Identifiers → your App ID (or create one) → enable the Sign In with Apple capability.
- Identifiers → + → Services IDs → create one (e.g.
com.yourapp.signin) → enable Sign In with Apple → configure it with your domain and redirect URL. This Services ID value is yourAPPLE_CLIENT_ID. - Keys → + → check Sign In with Apple, configure it against your App ID → Continue → Register → Download. The download is a one-time-only
.p8file — its contents go intoAPPLE_PRIVATE_KEY(keep the-----BEGIN PRIVATE KEY-----/-----END PRIVATE KEY-----wrapper,\n-escaped like the other multiline keys). The Key ID shown on that page isAPPLE_KEY_ID. - Your Team ID is shown in the top-right of the Apple Developer account page (or under Membership) — that's
APPLE_TEAM_ID. APPLE_REDIRECT_URIis the callback URL you configured on the Services ID in step 2 (only used for the web/backend OAuth flow — native Sign in with Apple on iOS doesn't need it).
The iOS app itself needs the Sign In with Apple capability added in Xcode (Signing & Capabilities) — already present in apps/ios/app/app/app.entitlements.
Apple Push Notifications (APNs)
Separate key from Sign in with Apple — used for VoIP push (incoming call alerts) and standard iOS push.
- Apple Developer → Keys → + → check Apple Push Notifications service (APNs) → Continue → Register → Download. Again, this
.p8is downloadable only once. - The key's contents go into
APNS_PRIVATE_KEY; the Key ID shown on the page isAPNS_KEY_ID. APNS_TEAM_IDis the same Team ID as above.APNS_BUNDLE_IDis your iOS app's bundle identifier (fromapp.xcodeproj).- Leave
APNS_PRODUCTION=falsefor a Debug/TestFlight build using the sandbox APNs environment; set totruefor App Store builds.
Stripe
- Sign up at dashboard.stripe.com.
- Developers → API keys — copy the Secret key (
sk_test_...while in test mode) intoSTRIPE_API_KEY_PROD_SECRET, and the Publishable key (pk_test_...) into the frontend'sNEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYand iOS'sSTRIPE_PUBLISHABLE_KEY. - Developers → Webhooks → Add endpoint — point it at
<API_URL>/webhooks/stripe(or wherever the backend exposes it), select the events the app needs (payment intents, subscription events), then copy the Signing secret intoSTRIPE_WEBHOOK_SECRET. For local testing, the Stripe CLI (stripe listen --forward-to localhost:8000/webhooks/stripe) prints a webhook secret you can use instead. - Switch to live keys (
sk_live_.../pk_live_...) only in production, after completing Stripe's account activation.
AWS (S3, SES, SNS)
- Create an AWS account if you don't have one, and sign in to the IAM console.
- Create an IAM user (or role) with programmatic access. Attach policies scoped to what you need:
AmazonS3FullAccess(or a bucket-scoped custom policy),AmazonSESFullAccess,AmazonSNSFullAccess— narrow these down for production. - IAM → Users → your user → Security credentials → Create access key — copy the Access key ID and Secret access key into
AWS_ACCESS_KEY/AWS_ACCESS_KEY_IDandAWS_SECRET_KEY/AWS_SECRET_ACCESS_KEY(both naming variants are read by different parts of the codebase — use the same values for both). - S3 bucket: S3 console → Create bucket, name it, note the region. Fill
AWS_BUCKET_NAMEandAWS_REGION;AWS_S3_URLishttps://<bucket>.s3.amazonaws.com. - SES (email): SES console → Verified identities → Create identity — verify a domain or individual sender email. While in the SES sandbox you can only send to verified addresses; request production access to send to any address. Set
AWS_EMAILto your verified sender. - SNS (SMS, only if using
SMS_PROVIDER=aws-sns): no separate signup — the same IAM credentials work; SNS is pay-as-you-go per SMS. - For local development without any of this, set
DISABLE_S3=trueandDISABLE_EMAIL=true.
Twilio (SMS / phone OTP)
Default SMS_PROVIDER.
- Sign up at twilio.com.
- Console dashboard shows your Account SID and Auth Token directly →
TWILIO_ACCOUNT_SID/TWILIO_AUTH_TOKEN. - Phone Numbers → Buy a number (trial accounts get one free) → copy it into
TWILIO_PHONE_NUMBER. - Verify → Services → Create new Service — this powers OTP codes specifically. Copy the Service SID into
TWILIO_VERIFY_SERVICE_SID. - For local development without SMS, set
DISABLE_SMS=true.
MessageBird (alternative SMS provider)
Only needed if you set SMS_PROVIDER=messagebird.
- Sign up at messagebird.com.
- Developers → API access → copy your Live API key (or Test key for sandbox) into
MESSAGEBIRD_API_KEY. MESSAGEBIRD_ORIGINATORis the sender name/number shown to recipients.
PayPal
- Sign up for a PayPal Developer account.
- Apps & Credentials → Create App (under Sandbox for testing, Live for production).
- Copy the Client ID and Secret into
PAYPAL_CLIENT_ID/PAYPAL_CLIENT_SECRET. PAYPAL_API_BASEdefaults to the sandbox URL (https://api-m.sandbox.paypal.com) — switch tohttps://api-m.paypal.comfor live.
In-app purchases (Apple & Google IAP)
For selling coins inside the native apps. See Coins → Native in-app purchases for how it works, and the env vars.
Apple (App Store Server API)
- First create the products: App Store Connect → your app → Monetization → In-App Purchases → Create a Consumable per coin package. Set its localized price tiers there (Apple localizes automatically), and copy each Product ID into its coin package in the admin
/coinsscreen (appleProductId). - Create an API key: App Store Connect → Users and Access → Integrations (Keys) → App Store Connect API → generate a key with the In-App Purchase (or Admin) role. Download the
.p8(once only). - Map to env: the page shows the Issuer ID →
APPLE_IAP_ISSUER_ID; the key's Key ID →APPLE_IAP_KEY_ID; the.p8contents →APPLE_IAP_PRIVATE_KEY; your bundle id →APPLE_IAP_BUNDLE_ID. - Notifications (refunds): App Store Connect → your app → General → App Store Server Notifications → Version 2, set the Production/Sandbox URL to
https://<your-api>/api/webhooks/apple/iap. To pin the signature, download Apple Root CA — G3 from Apple PKI and put its PEM inAPPLE_IAP_ROOT_CERT(required — the Apple refund webhook fails closed and rejects notifications without a pinned root).
Google (Play Developer API + RTDN)
- First create the products: Play Console → your app → Monetize → Products → In-app products → Create a managed product per coin package. Copy each Product ID into its coin package in admin (
googleProductId).GOOGLE_IAP_PACKAGE_NAMEis your app'sapplicationId. - Service account: in Google Cloud Console create a service account + JSON key; then in Play Console → Users and permissions → invite that service account and grant View financial data / Manage orders and subscriptions. Put the JSON (stringified) in
GOOGLE_IAP_SERVICE_ACCOUNT_KEY. - Refunds (Voided Purchases + RTDN): enable Play Console → Monetization setup → Real-time developer notifications, point the topic at a Google Cloud Pub/Sub topic, and add a push subscription to that topic delivering to
https://<your-api>/api/webhooks/google/rtdn. To verify the push, setGOOGLE_RTDN_AUDIENCE(your webhook URL) andGOOGLE_RTDN_SA_EMAIL(the Pub/Sub push service account) — optional but recommended.
Google Cloud Vision (image moderation)
Used for NSFW/content-label detection (IMAGE_ANALYSIS_PROVIDER=google-vision). Uses the same kind of service-account credentials as BigQuery below — you can reuse one service account for both if it has both APIs enabled.
- In Google Cloud Console, enable the Cloud Vision API for your project (APIs & Services → Library → Cloud Vision API → Enable).
- IAM & Admin → Service Accounts → Create Service Account, grant it a role like Cloud Vision AI Service Agent (or broader if reusing for BigQuery).
- Keys → Add key → Create new key → JSON — download it. The backend's image-analysis service picks up credentials the standard Google Cloud way; check
services/image-analysis/image-analysis.service.jsfor exactly which env var(s) it expects the credentials path/JSON in before wiring this up, since it isn't one of the explicitly-named.env.examplevariables.
BigQuery (analytics, optional)
Only needed if you set ANALYTICS_DB_TYPE=bigquery — the default (postgres) needs no external account at all.
- In Google Cloud Console, enable the BigQuery API.
- IAM & Admin → Service Accounts → Create Service Account, grant it BigQuery Data Editor and BigQuery Job User.
- Keys → Add key → Create new key → JSON — map the downloaded file's fields to
BIGQUERY_PRIVATE_KEY_ID,BIGQUERY_PRIVATE_KEY,BIGQUERY_CLIENT_EMAIL,BIGQUERY_CLIENT_ID. - BigQuery console → Create dataset — note the dataset ID and location for
BIGQUERY_DATASET_ID/BIGQUERY_LOCATION. GOOGLE_CLOUD_PROJECT_ID/GCP_PROJECT_IDis your GCP project ID, visible on the Cloud Console dashboard.
Giphy (iOS GIF picker)
- Sign up at developers.giphy.com.
- Create an App → choose the API key type (not SDK).
- Copy the key into iOS's
GIPHY_API_KEY(Xcode scheme environment variable — see Environment Setup).
Observability (all optional)
These only matter once you care about production monitoring — skip them entirely for local development.
- Sentry — create a project, copy the DSN from Project Settings → Client Keys into
SENTRY_DSN. - Datadog — Organization Settings → API Keys → create/copy one into
DATADOG_API_KEY. - New Relic — Account settings → API keys → copy an Ingest - License key into
NEW_RELIC_LICENSE_KEY. - LogRocket — Project Settings → copy the App ID (format
org/project) intoLOGROCKET_APP_ID. - Custom logger (
CUSTOM_LOGGER_URL/CUSTOM_LOGGER_API_KEY) — only relevant if you're pointing logs at your own ingestion endpoint; not tied to a specific third-party product.