Layers

Configure auto-pilot engagement

First-comments at publish and auto-replies to incoming comments, tuned to brand voice and rate-limited per post.

View as Markdown

What you'll build

A running auto-pilot for the comments under a customer's posts: a first-comment that drops at publish, and auto-replies on incoming comments. Both are tuned to the project's brand voice, and both pass through a moderation gate before anything goes out.

This is a configuration flow — you read the current engagement config, patch the fields you want, and the running cadence picks it up on the next post. There's no separate job or workflow call.

Only the v1 engagement template shape is exposed today. Sending v2 fields like replies.tone, replies.maxPerPostPerHour, or firstComment.strategy returns 403 FORBIDDEN_FENCE. Those are planned. The template itself supports them today; the API doesn't widen until then.

Read the current engagement config

Every project has a Social Engagement layer. Calling GET fetches the v1 config shape — any v2 fields currently set in the database are stripped from the response.

GET/v1/projects/:projectId/engagement
Phase 1stable
Auth
Bearer
Scope
engagement:write
curl "https://api.layers.com/v1/projects/$PROJECT_ID/engagement" \
  -H "Authorization: Bearer $LAYERS_API_KEY"
200
{
  "enabled": false,
  "firstComment": {
    "targets": [],
    "commentTemplate": ""
  },
  "replyToComments": {
    "targets": [],
    "autoReplyDelay": "PT3M"
  }
}

Defaults are empty and enabled: false — nothing ships until you turn it on.

Enable first-comments

First-comments drop automatically within a few seconds of publish. Typical use: call-to-action that didn't fit the caption, app link, "DM for the recipe", etc.

PATCH/v1/projects/:projectId/engagement
Phase 1stable
Auth
Bearer
Scope
engagement:write
curl -X PATCH "https://api.layers.com/v1/projects/$PROJECT_ID/engagement" \
  -H "Authorization: Bearer $LAYERS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "firstComment": {
      "targets": ["tiktok", "instagram"],
      "commentTemplate": "Grab the app — link in bio. First order is on us ☕️"
    }
  }'
const res = await fetch(
  `https://api.layers.com/v1/projects/${projectId}/engagement`,
  {
    method: "PATCH",
    headers: {
      Authorization: `Bearer ${process.env.LAYERS_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      enabled: true,
      firstComment: {
        targets: ["tiktok", "instagram"],
        commentTemplate: "Grab the app — link in bio. First order is on us ☕️",
      },
    }),
  },
);
import os
import requests

requests.patch(
    f"https://api.layers.com/v1/projects/{project_id}/engagement",
    headers={
        "Authorization": f"Bearer {os.environ['LAYERS_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "enabled": True,
        "firstComment": {
            "targets": ["tiktok", "instagram"],
            "commentTemplate": "Grab the app — link in bio. First order is on us ☕️",
        },
    },
)

commentTemplate is a literal string — no interpolation today. The same template drops under every post on every target platform. If you need per-post customization, pass firstCommentOverride on the schedule call instead (see Schedule).

If you see VALIDATION with data.field: "targets", you passed a platform the project doesn't have a distribution layer for. Run GET /v1/projects/:id and check layers[] — only platforms with a distribution layer can be engagement targets.

Enable auto-replies

Auto-replies respond to incoming comments on published posts, passing every reply through a moderation gate before it goes live.

curl -X PATCH "https://api.layers.com/v1/projects/$PROJECT_ID/engagement" \
  -H "Authorization: Bearer $LAYERS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "replyToComments": {
      "targets": ["tiktok", "instagram"],
      "autoReplyDelay": "PT5M"
    }
  }'

autoReplyDelay is an ISO-8601 duration (PT30S, PT5M, PT1H) — short enough to feel responsive, long enough that replies don't stack up on the post's top shelf. PT3M is the default and works for most accounts.

Replies are LLM-generated, tuned to the project's brandContext.brandVoice, and filtered by a safety layer before posting. Nothing ships that fails moderation — the comment is silently skipped and logged for review. Escalating negative-sentiment comments to human review is planned.

Turn it off

Set enabled: false to stop everything. First-comments drop, auto-replies drop, in-flight replies cancel.

curl -X PATCH "https://api.layers.com/v1/projects/$PROJECT_ID/engagement" \
  -H "Authorization: Bearer $LAYERS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": false }'

Use the master switch rather than emptying the targets arrays — it's faster to restore, and it keeps the config intact so you can re-enable without re-patching everything.

What you can't do yet

The planned v2 template widens the shape with these fields:

  • firstComment.strategy — pick between literal (today's behavior) and generated (LLM-written per post from brand voice + caption).
  • replies.tone — override the project's default brand voice for replies specifically.
  • replies.maxPerPostPerHour — rate cap for auto-replies on a single post.
  • replies.ignoreCommentsMatching — regex allowlist of comment shapes to skip.
  • replies.escalateNegativeSentiment — route negative-sentiment comments to a human review queue instead of auto-replying.

If you try to PATCH with any of these today, you get 403 FORBIDDEN_FENCE and the body names the offending field. Don't work around it by sending them through a different path — the database layer enforces the fence too.

What's next

On this page