Integrations
The integrations command mirrors the /integrations page and the
per-slug detail pages it links to. Backend integrations are split into
three coupled surfaces:
| Surface | Purpose |
|---|---|
| configs | Per-slug behavior — which template fires on which event, with what variable mappings |
| accounts | OAuth connections to third-party platforms (Pipedream-style) |
| logs | Webhook events received from the third party, with replay/inspection |
Backed by /api/v1/app/integrations/*.
Quick start
# 1. See what's wired up
splashify integrations # configs (default view)
splashify integrations accounts # OAuth connections
# 2. Save a Shopify config
splashify integrations config shopify save \
--enabled true \
--template <template_id> \
--template-name "order_shipped" \
--template-language en \
--vars '{"{{1}}":"contact.first_name","{{2}}":"event.order_id"}' \
--phone-field "customer.phone" \
--config '{"webhook_secret":"shpss_…"}'
# 3. Watch incoming webhooks
splashify integrations logs --slug shopify --limit 50Command tree
integrations list per-slug configs (default)
integrations configs same
integrations config <slug> show one config
integrations config <slug> save … update/create
integrations config <slug> delete remove the config (the slug stays available)
integrations accounts list OAuth connections
integrations account <id> show one
integrations account <id> disconnect revoke
integrations token mint a connect-token for OAuth callbacks
integrations logs [--limit] [--slug] webhook event feed
integrations log <log_id> show one eventPer-slug configs
A config tells the backend: when a webhook event from this slug arrives, which WhatsApp template do I fire and what variables do I substitute?
# Show one
splashify integrations config shopify
# Save (creates if absent, updates if present — PUT semantics)
splashify integrations config shopify save \
--enabled true \
--template <template_id>
# Delete
splashify integrations config shopify delete| Backed by | PUT /api/v1/app/integrations/configs/:slug |
|---|---|
DELETE /api/v1/app/integrations/configs/:slug |
The endpoint is gated by your plan’s allowed_integrations list — if
the slug isn’t included, the backend refuses with the standard
plan_required error. An empty list on the plan means all available.
Save flags
| Flag | What it sets |
|---|---|
--enabled | true to make the integration active |
--template | template_id of the fallback WhatsApp template |
--template-name | template name (display only) |
--template-language | BCP-47 language for the template |
--config | JSON object of provider secrets — e.g. '{"api_key":"…","webhook_secret":"…"}' |
--vars | JSON object mapping template variables to webhook payload paths — '{"{{1}}":"contact.first_name"}' |
--phone-field | webhook payload field that holds the phone number |
--events | nested JSON: per-event template overrides — see below |
Per-event automations
--events lets you bind specific webhook events to different templates,
e.g. send order_shipped for order.shipped but payment_failed for
payment.failed. The value is a JSON object keyed by event name:
splashify integrations config shopify save \
--events '{
"order.shipped": {
"template_id": "<shipped_template_id>",
"template_name": "order_shipped",
"variable_mappings": {"{{1}}":"customer.first_name","{{2}}":"order.tracking_url"},
"phone_field": "customer.phone"
},
"payment.failed": {
"template_id": "<failed_template_id>",
"template_name": "payment_failed",
"variable_mappings": {"{{1}}":"customer.first_name","{{2}}":"order.id"},
"phone_field": "customer.phone"
}
}'Per-event mappings override the top-level --template / --vars /
--phone-field when the incoming event matches.
OAuth connections (accounts)
Some integrations connect via OAuth instead of webhook secret. Those mint account records on success.
splashify integrations accounts # list all
splashify integrations account <account_id> # show one
splashify integrations account <account_id> disconnect # revoke| Backed by | GET /api/v1/app/integrations/accounts |
|---|---|
DELETE /api/v1/app/integrations/accounts/:account_id |
Connect tokens
Some OAuth flows hand a short-lived connect-token to the third party so the redirect can attribute the connection back to your account.
splashify integrations token| Backed by | POST /api/v1/app/integrations/token |
|---|
Returns a one-shot token you pass to the third party’s OAuth URL as
state or equivalent.
Webhook logs
Every incoming webhook is recorded for inspection + replay.
splashify integrations logs # newest first, server default
splashify integrations logs --limit 200
splashify integrations logs --slug shopify # filter to one integration
splashify integrations log <log_id> # one event in detail| Backed by | GET /api/v1/app/integrations/logs[?limit=&slug=] |
|---|---|
GET /api/v1/app/integrations/logs/:log_id |
Each log row carries the raw payload, the event type, the slug, the template that fired (if any), and the resulting send status. Use this to debug “why didn’t my Shopify webhook send a WhatsApp?”
Common workflows
Audit which integrations fired in the last hour
CUTOFF=$(date -u -v-1H '+%Y-%m-%dT%H:%M:%SZ') # macOS
# CUTOFF=$(date -u -d '1 hour ago' '+%Y-%m-%dT%H:%M:%SZ') # linux
splashify integrations logs --limit 500 | \
jq --arg c "$CUTOFF" '.logs[] | select(.created_at > $c) |
{created_at, slug, event_type, status}'Find the most-recent failed delivery for a slug
splashify integrations logs --slug shopify --limit 200 | \
jq '[.logs[] | select(.status == "failed")] | first |
{log_id, event_type, error, raw_payload}'Disable every integration at once (emergency stop)
splashify integrations configs | \
jq -r '.configs[] | select(.enabled) | .slug' | \
xargs -I{} splashify integrations config {} save --enabled falseBackup all configs before a change
splashify integrations configs > integrations.backup.json
# Restore one slug from the backup:
SLUG=shopify
jq -c --arg s "$SLUG" '.configs[] | select(.slug == $s)' integrations.backup.json
# Then translate to a save command…Disconnect every Pipedream account
splashify integrations accounts | \
jq -r '.accounts[] | select(.provider == "pipedream") | .account_id' | \
xargs -I{} splashify integrations account {} disconnectTroubleshooting
plan_required on config <slug> save — the slug isn’t in your
plan’s allowed_integrations list. Check splashify subscription for
add-on options.
config save returns 200 but webhook doesn’t fire a WhatsApp —
likely a mapping problem. Check splashify integrations logs --slug <slug> for the raw payload, then verify each --vars path resolves
against it. Most common cause: --phone-field pointing at the wrong
property.
Webhook URL — the per-slug receiver is at
/webhooks/integrations/:user_id/:slug (public, no auth — it’s gated
by signature/secret verification against the webhook_secret you set
in --config). Provider docs should point there.
account disconnect 200 but the connection still works — some
providers cache tokens client-side for a few minutes. The next webhook
event from them will fail (no matching account record), so deliveries
stop within ~minutes.
See also
splashify templates— the source oftemplate_id/template_namevalues used in configs.splashify subscription— see which integrations are allowed on your plan.