> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mapping.travel/llms.txt
> Use this file to discover all available pages before exploring further.

# Recipe: Push results to a webhook

> Send mapping job results to your own HTTPS endpoint on job completion.

When a mapping job finishes, you might want the results in your own data warehouse, BI tool, or app — without polling our API. This recipe wires an agent to `POST` the result payload to your HTTPS endpoint on every job completion.

<Warning>
  Outbound push is **default off** because it sends your data to a destination of your choice — explicit opt-in is required. Pushes are also **not undoable** (egress side effect). Test thoroughly before flipping `auto_push_on_job_complete` to `true` in production.
</Warning>

## Prerequisites

* Pro Max workspace.
* An HTTPS endpoint you control that accepts `POST` + JSON.
* One of three auth schemes: Bearer, HMAC-SHA256, or Basic.

## Steps

<Steps>
  <Step title="Create the agent">
    Or use an existing one — sinks attach to any agent.
  </Step>

  <Step title="Add the outbound sink">
    **Data sources → Add → HTTPS webhook (outbound).**

    * `name`: *"Internal BI ingest"*
    * `url`: `https://internal.acme.com/mapping-results`
    * `authScheme`: `HmacSha256`
    * `secret`: paste a 32-byte secret (stored in vault).
    * `format`: `JSON`
  </Step>

  <Step title="Test the endpoint">
    Click **Test** — we send a synthetic payload signed with your secret. You should see the request hit your endpoint with `X-MT-Signature: sha256=<hex>` header.
  </Step>

  <Step title="Enable auto-push in rules">
    ```json theme={null}
    {
      "data_sinks": {
        "auto_push_on_job_complete": true,
        "retry_failed_push": 2
      }
    }
    ```
  </Step>

  <Step title="Activate the agent">
    Next finished mapping job triggers a push.
  </Step>
</Steps>

## Payload shape

```json theme={null}
{
  "jobId": "job_01J...",
  "agentId": "agt_01J...",
  "workspaceId": "ws_01J...",
  "completedAt": "2026-05-25T12:34:56Z",
  "stats": { "total": 12000, "matched": 11540, "unmatched": 460 },
  "results": [
    { "partnerRowId": "row_01J...", "referenceHotelId": "ref_01J...", "matchMethod": "STANDARD", "matchConfidence": null },
    { "partnerRowId": "row_02J...", "referenceHotelId": null, "matchMethod": null, "matchConfidence": null }
  ]
}
```

## HMAC verification (Node)

```js theme={null}
const crypto = require('crypto');

app.post('/mapping-results', (req, res) => {
  const sig = req.headers['x-mt-signature'].replace('sha256=', '');
  const expected = crypto
    .createHmac('sha256', process.env.MT_WEBHOOK_SECRET)
    .update(req.rawBody)
    .digest('hex');
  if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
    return res.status(401).end();
  }
  // ... handle req.body ...
  res.status(200).end();
});
```

## Retry semantics

* Initial attempt + `retry_failed_push` retries (default 2).
* Exponential backoff: 5s, 30s, 5min.
* 4xx responses are not retried (you returned them deliberately).
* 5xx and timeouts retry.
* All attempts land in `agent_data_source_sync` with per-attempt status.

## Equivalent API call

```bash theme={null}
curl -X POST https://api.mapping.travel/api/v1/agents/{id}/data-sources \
  -H 'Authorization: Bearer mt_...' \
  -d '{
    "role": "RESULTS_SINK",
    "type": "HTTPS_WEBHOOK",
    "name": "Internal BI ingest",
    "config": { "url": "https://internal.acme.com/mapping-results", "authScheme": "HmacSha256" },
    "secret": { "value": "..." },
    "format": "JSON"
  }'
```

## Related

* [Agents overview](/agents/overview) — broader context.
* [Data sources and sinks](/agents/data-sources-and-sinks) — auth scheme details.
* [Audit and undo](/agents/audit-and-undo) — why push is not undoable.
