HTTP requests

Call any API after a decision — method, URL, headers and a JSON body built from variables and workspace secrets — delivered with retries, an Idempotency-Key and a signature.

An API request destination (type http) calls any HTTP API with a request you design — create a lead in your CRM, open a ticket, post to Slack — in the background, with retries. Tokens stay in workspace secrets, never in the decision.

Configure it

{
  "key": "create_lead",
  "type": "http",
  "when": { "conditions": [{ "field": "route", "on": "output", "operator": "eq", "value": "sales" }] },
  "params": {
    "email": { "from": "state.email", "required": true },
    "score": { "from": "composites.lead_score" }
  },
  "http": {
    "method": "POST",
    "url": "https://api.crm.example.com/v2/leads?source={{decision.slug}}",
    "headers": [{ "name": "Authorization", "value": "Bearer {{secrets.CRM_TOKEN}}" }],
    "body": "{\"email\": {{params.email}}, \"score\": {{params.score}}, \"note\": \"Routed to {{result.route}} by Dcision\"}"
  }
}
FieldTypeDefaultDescription
methodstringPOSTGET, POST, PUT, PATCH or DELETE.
urlstring—https://… or {{secrets.NAME}} holding the whole URL; up to 2,048 characters, variables URL-encoded.
headersarray[]Up to 20 { "name", "value" } pairs; values up to 2,048 characters, with variables and secrets.
bodystringthe params as JSONPOST, PUT and PATCH only: a JSON template of up to 10,000 characters.

The body

The body is a JSON template: outside quotes a variable becomes a JSON value, inside quotes it becomes text — see JSON bodies. With the destination above, the CRM receives:

{ "email": "ana@acme.com", "score": 0.8414, "note": "Routed to sales by Dcision" }
  • No body template on POST, PUT or PATCH: the params are sent as a JSON object.
  • Content-Type: application/json is set unless you add your own Content-Type header.
  • GET and DELETE have no body — a body on them is a schema error. Their params are added to the query string (?email=ana%40acme.com&score=0.8414), unless the URL already uses {{params.…}}.

Headers

Your headers are sent with Dcision's:

HeaderValue
Your headersTheir values rendered as text — line breaks become spaces.
Content-Typeapplication/json when there is a body, unless you set it.
User-AgentDcision-Destinations/1.0 (+https://docs.dcision.io/destinations), unless you set it.
Idempotency-KeyThe delivery ID, dlv_…, unless you set it — the same on every attempt, so APIs that support idempotency keys never apply a retry twice.
Dcision-Delivery, Dcision-Attempt, Dcision-Event, Dcision-SignatureAs for webhooks.

Some names are set by Dcision or the HTTP layer and can't be used: Host, Content-Length, Connection, Transfer-Encoding, Upgrade, Keep-Alive, TE, Trailer, Expect, and any name that starts with Proxy- or Dcision-.

Authentication

Put credentials in a header with a secret — Authorization: Bearer {{secrets.CRM_TOKEN}} — or in the URL as a secret when the API expects a secret URL ({{secrets.SLACK_WEBHOOK}}). Credentials in the URL itself (https://user:password@…) are refused.

The signature

API requests are signed like webhooks, over the exact body sent — an empty body for GET and DELETE. If the receiving API is yours, verify Dcision-Signature with verifySignature (TypeScript) or verify_signature (Python): the body is your template, not a webhook event. See Verify the signature.

Example: a Slack message

Slack's incoming webhooks expect their own JSON, so use an API request with the webhook URL stored as a secret:

{
  "key": "escalation_alert",
  "type": "http",
  "when": { "actions": ["escalate"] },
  "params": { "message": { "from": "state.message" } },
  "http": {
    "method": "POST",
    "url": "{{secrets.SLACK_WEBHOOK}}",
    "body": "{\"text\": \"{{decision.slug}} asks for a person ({{action}}): {{params.message}}\"}"
  }
}

The message is written inside quotes, so the param is inserted as escaped text — quotes and line breaks in the lead's message can't break the JSON.

On this page