rollfuse
← Back to tutorials

Sync external metrics into rollfuse with connectors

A connector is a project-scoped configuration that pulls data from an external HTTP source you already run, on a schedule, and records each entry as an Observation against a metric definition and environment inside rollfuse. This is what feeds guardrails and rollout metrics with numbers your own systems already produce, instead of asking every service to push data to rollfuse directly. This walks through configuring a connector, previewing its mapping before you save anything, and forcing a sync on demand.

Preview the mapping before saving anything

Before creating a connector, confirm the mapping actually resolves against your live source with POST /v1/projects/{project_id}/connectors/preview. This fetches source_url once, applies the mapping you supply, and never persists a connector, a contract template version, or an observation:

const response = await fetch(
  `https://api.rollfuse.com/v1/projects/${projectId}/connectors/preview`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      source_url: "https://billing.example.com/metrics",
      secret: "s3cr3t",
      root_path: ".",
      value_field: "amount",
      observed_at_field: "observed_at",
      observed_at_format: "rfc3339",
    }),
  },
);

const preview = await response.json();

if (preview.error) {
  console.error("mapping did not resolve:", preview.error, preview.raw_response);
} else {
  console.log("resolved observations:", preview.observations);
}

raw_response is always present, so a failed mapping still shows you exactly what the source returned, which is usually enough to spot the wrong field name.

Create the connector

Once the mapping resolves, create the connector with POST /v1/projects/{project_id}/connectors, pointing it at the metric definition and environment it should feed:

const response = await fetch(
  `https://api.rollfuse.com/v1/projects/${projectId}/connectors`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Billing metrics",
      template_id: templateId,
      source_url: "https://billing.example.com/metrics",
      secret: "s3cr3t",
      metric_definition_id: metricDefinitionId,
      environment_id: environmentId,
    }),
  },
);

const connector = await response.json();
console.log(connector.id, connector.status);

The response is the only place the plaintext pull secret is returned; a later GET on the connector never includes it. The connector is pinned at creation to a specific, approved contract template version, so approving a newer template version later never silently changes how this connector behaves.

Force a sync on demand

Connectors pull on their own schedule, but you can trigger an immediate sync with POST /v1/connectors/{connector_id}/sync, useful right after creating a connector or while debugging a mapping change:

const response = await fetch(
  `https://api.rollfuse.com/v1/connectors/${connector.id}/sync`,
  { method: "POST", headers: { Authorization: `Bearer ${token}` } },
);

if (!response.ok) {
  const error = await response.json();
  console.error("sync failed:", error);
} else {
  const synced = await response.json();
  console.log("last sync ok, status:", synced.status);
}

A failed sync (source unreachable, non-2xx response, an unparseable body, or a downstream recording failure) records no observation at all and leaves the connector's last-sync-failed state visible on the next GET, so a bad source never silently writes partial data into your metric history.

Turning a connector off

Disable a connector instead of deleting it if you need to stop pulling from a source without losing its configuration or sync history:

await fetch(`https://api.rollfuse.com/v1/connectors/${connector.id}/disable`, {
  method: "POST",
  headers: { Authorization: `Bearer ${token}` },
});

A disabled connector rejects further sync requests, but its configuration and history stay intact.

Tool-specific setup

A connector's source_url can point at anything that returns HTTP data on request, including an exporter or API you already run for an observability tool. For the reference on getting metric data out of a specific tool in the first place, see the integration pages for Prometheus, Grafana, and Datadog, rather than duplicating that setup here.