Skip to main content

Connection Creation

The Datagrid API provides an iframe-based embedding solution for connection creation that allows you to integrate third-party service authentication flows directly into your application.

Overview

When you need to create connections to third-party services (like Google Drive, Hubspot, Dropbox, etc.), you can embed the Datagrid API connection creation flow in an iframe. The iframe will handle the OAuth flow and authentication, then communicate the results back to your parent application via postMessage events. There are two main flows:
  1. Connection Creation - Authenticate with a third-party service to create a connection
  2. Knowledge from Connection - Use an existing connection to import data as knowledge for your agents

API Flow

Before embedding the iframes, you need to call the appropriate API endpoints to get the redirect URLs.

Step 1: Create a Connection

To create a connection, call the createConnectionRedirectUrl endpoint:
// Get the redirect URL for creating a new connection
const { redirect_url } = await datagridClient.connections.createConnectionRedirectUrl({
  connector_id: "google_drive", // The connector type (google_drive, hubspot, dropbox, etc.)
});

// Use this redirect_url with the ConnectionEmbed component

Step 2: Create Knowledge from Connection (Optional)

After a connection is created, you can create knowledge from it. Call the createKnowledgeFromConnection endpoint:
// Get the redirect URL for creating knowledge from an existing connection
const { redirect_url } = await datagridClient.knowledge.createKnowledgeFromConnection({
  connection_id: "conn_abc123", // The ID of the connection created in Step 1
});

// Use this redirect_url with the KnowledgeFromConnectionEmbed component

Connection Embed Implementation

The ConnectionEmbed component handles the connection creation flow. It receives the redirect_url from the createConnectionRedirectUrl API call. Here’s a React component example that demonstrates how to embed the connection creation iframe:
import React, { FC, useRef, useEffect, useState } from "react";
import { Typography, Box } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";

const useStyles = makeStyles((theme) => ({
  root: {
    height: "100%",
    width: "100%",
    flex: 1,
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
  },
  iframeWrapper: {
    display: "flex",
    flexDirection: "column",
    gap: theme.spacing(4),
  },
  iframe: {
    border: "none",
    borderRadius: theme.spacing(1),
    boxShadow: theme.shadows[2],
  },
}));

interface ConnectionEmbedProps {
  redirectUrl: string;
  onConnectionCreated?: (connection: any) => void;
  onConnectionUpdated?: (connection: any) => void;
  onError?: (error: any) => void;
}

const ConnectionEmbed: FC<ConnectionEmbedProps> = ({
  redirectUrl,
  onConnectionCreated,
  onConnectionUpdated,
  onError,
}) => {
  const classes = useStyles();
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const [iframeHeight, setIframeHeight] = useState(600);

  useEffect(() => {
    const handleMessage = (event: MessageEvent) => {
      // Only process messages from datagrid-api
      if (!event.data.type || !event.data.type.includes("datagrid-api")) {
        return;
      }

      console.log("Received iframe message:", event.data);

      switch (event.data.type) {
        case "datagrid-api/connection-created":
          console.log("Connection created:", event.data.payload);
          onConnectionCreated?.(event.data.payload);
          break;

        case "datagrid-api/connection-updated":
          console.log("Connection updated:", event.data.payload);
          onConnectionUpdated?.(event.data.payload);
          break;

        case "datagrid-api/error":
          console.error("Iframe error:", event.data.payload);
          onError?.(event.data.payload);
          break;

        case "datagrid-api/resize":
          const { height, width } = event.data.payload;
          setIframeHeight(height);
          console.log(`Iframe resized to: ${width}x${height}`);
          break;

        case "datagrid-api/content-loaded":
          console.log("Iframe content loaded");
          break;

        default:
          console.log("Unknown iframe event:", event.data.type);
      }
    };

    window.addEventListener("message", handleMessage);

    return () => {
      window.removeEventListener("message", handleMessage);
    };
  }, [onConnectionCreated, onConnectionUpdated, onError]);

  return (
    <div className={classes.root}>
      <div className={classes.iframeWrapper}>
        <Typography variant="h6">Connect Your Service</Typography>
        <iframe
          className={classes.iframe}
          ref={iframeRef}
          src={redirectUrl}
          width="400px"
          height={`${iframeHeight}px`}
          title="Connection Creation"
        />
      </div>
    </div>
  );
};

export default ConnectionEmbed;

Connection Embed Usage Example

import ConnectionEmbed from "./ConnectionEmbed";

function App() {
  const [redirectUrl, setRedirectUrl] = useState("");

  useEffect(() => {
    const initConnection = async () => {
      try {
        // Use createConnectionRedirectUrl to get the redirect URL
        const { redirect_url } = await datagridClient.connections.createConnectionRedirectUrl({
          connector_id: "google_drive",
        });
        setRedirectUrl(redirect_url);
      } catch (err) {
        console.error("Failed to create connection:", err);
      }
    };

    initConnection();
  }, []);

  const handleConnectionCreated = (connection) => {
    console.log("New connection:", connection);
    // Handle the newly created connection
    // You can store it, redirect user, etc.
  };

  const handleError = (error) => {
    console.error("Connection error:", error);
    // Handle any errors that occur during connection creation
  };

  if (!redirectUrl) {
    return <noscript />;
  }

  return (
    <ConnectionEmbed
      redirectUrl={redirectUrl}
      onConnectionCreated={handleConnectionCreated}
      onError={handleError}
    />
  );
}

Knowledge from Connection Embed

After creating a connection, you can use it to import data as knowledge for your agents. The KnowledgeFromConnectionEmbed component handles this flow.

KnowledgeFromConnectionEmbed Component

This component receives the redirect_url from the createKnowledgeFromConnection API call:
import React, { FC, useRef, useEffect, useState } from "react";
import { Typography, Box } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";

const useStyles = makeStyles((theme) => ({
  root: {
    height: "100%",
    width: "100%",
    flex: 1,
    display: "flex",
    flexDirection: "column",
    alignItems: "center",
    justifyContent: "center",
  },
  iframeWrapper: {
    display: "flex",
    flexDirection: "column",
    gap: theme.spacing(4),
  },
  iframe: {
    border: "none",
    borderRadius: theme.spacing(1),
    boxShadow: theme.shadows[2],
  },
}));

interface KnowledgeFromConnectionEmbedProps {
  redirectUrl: string;
  onKnowledgeCreated?: (payload: { knowledge_id: string }) => void;
  onError?: (error: { message: string; error: object | null }) => void;
}

const KnowledgeFromConnectionEmbed: FC<KnowledgeFromConnectionEmbedProps> = ({
  redirectUrl,
  onKnowledgeCreated,
  onError,
}) => {
  const classes = useStyles();
  const iframeRef = useRef<HTMLIFrameElement>(null);
  const [iframeHeight, setIframeHeight] = useState(600);

  useEffect(() => {
    const handleMessage = (event: MessageEvent) => {
      // Only process messages from datagrid-api
      if (!event.data.type || !event.data.type.includes("datagrid-api")) {
        return;
      }

      console.log("Received iframe message:", event.data);

      switch (event.data.type) {
        case "datagrid-api/knowledge-created":
          console.log("Knowledge created:", event.data.payload);
          onKnowledgeCreated?.(event.data.payload);
          break;

        case "datagrid-api/error":
          console.error("Iframe error:", event.data.payload);
          onError?.(event.data.payload);
          break;

        case "datagrid-api/resize":
          const { height, width } = event.data.payload;
          setIframeHeight(height);
          console.log(`Iframe resized to: ${width}x${height}`);
          break;

        case "datagrid-api/content-loaded":
          console.log("Iframe content loaded");
          break;

        default:
          console.log("Unknown iframe event:", event.data.type);
      }
    };

    window.addEventListener("message", handleMessage);

    return () => {
      window.removeEventListener("message", handleMessage);
    };
  }, [onKnowledgeCreated, onError]);

  return (
    <div className={classes.root}>
      <div className={classes.iframeWrapper}>
        <Typography variant="h6">Select Data to Import</Typography>
        <iframe
          className={classes.iframe}
          ref={iframeRef}
          src={redirectUrl}
          width="400px"
          height={`${iframeHeight}px`}
          title="Knowledge Creation"
        />
      </div>
    </div>
  );
};

export default KnowledgeFromConnectionEmbed;

Knowledge from Connection Usage Example

import KnowledgeFromConnectionEmbed from "./KnowledgeFromConnectionEmbed";

function App() {
  const [redirectUrl, setRedirectUrl] = useState("");
  const connectionId = "conn_abc123"; // The connection ID from a previously created connection

  useEffect(() => {
    const initKnowledge = async () => {
      try {
        // Use createKnowledgeFromConnection to get the redirect URL
        // For display purposes, the datagrid API is invoked inline
        // In a production setting, this needs to be proxied through your backend to avoid leaking any secrets
        const { redirect_url } = await datagridClient.knowledge.createKnowledgeFromConnection({
          connection_id: connectionId,
        });
        setRedirectUrl(redirect_url);
      } catch (err) {
        console.error("Failed to initiate knowledge creation:", err);
      }
    };

    initKnowledge();
  }, [connectionId]);

  const handleKnowledgeCreated = (payload: { knowledge_id: string }) => {
    console.log("Knowledge created with ID:", payload.knowledge_id);
    // Handle the newly created knowledge
    // You can fetch knowledge details, redirect user, etc.
  };

  const handleError = (error) => {
    console.error("Knowledge creation error:", error);
    // Handle any errors that occur during knowledge creation
  };

  if (!redirectUrl) {
    return <noscript />;
  }

  return (
    <KnowledgeFromConnectionEmbed
      redirectUrl={redirectUrl}
      onKnowledgeCreated={handleKnowledgeCreated}
      onError={handleError}
    />
  );
}

Complete Flow Example

Here’s an example showing the complete flow from connection creation to knowledge import:
import { useState } from "react";
import ConnectionEmbed from "./ConnectionEmbed";
import KnowledgeFromConnectionEmbed from "./KnowledgeFromConnectionEmbed";

function ConnectionToKnowledgeFlow() {
  const [step, setStep] = useState<"connection" | "knowledge">("connection");
  const [connectionRedirectUrl, setConnectionRedirectUrl] = useState("");
  const [knowledgeRedirectUrl, setKnowledgeRedirectUrl] = useState("");
  const [connectionId, setConnectionId] = useState("");

  // Step 1: Initialize connection creation
  useEffect(() => {
    const initConnection = async () => {
      const { redirect_url } = await datagridClient.connections.createConnectionRedirectUrl({
        connector_id: "google_drive",
      });
      setConnectionRedirectUrl(redirect_url);
    };
    initConnection();
  }, []);

  // Step 2: When connection is created, get knowledge redirect URL
  const handleConnectionCreated = async (connection) => {
    console.log("Connection created:", connection.id);
    setConnectionId(connection.id);

    // Get the redirect URL for knowledge creation
    // For display purposes, the datagrid API is invoked inline
    // In a production setting, this needs to be proxied through your backend to avoid leaking any secrets
    const { redirect_url } = await datagridClient.knowledge.createKnowledgeFromConnection({
      connection_id: connection.id,
    });
    setKnowledgeRedirectUrl(redirect_url);
    setStep("knowledge");
  };

  // Step 3: Handle knowledge creation completion
  const handleKnowledgeCreated = (payload) => {
    console.log("Knowledge created:", payload.knowledge_id);
    // Flow complete! The agent can now use this knowledge.
  };

  if (step === "connection" && connectionRedirectUrl) {
    return (
      <ConnectionEmbed
        redirectUrl={connectionRedirectUrl}
        onConnectionCreated={handleConnectionCreated}
      />
    );
  }

  if (step === "knowledge" && knowledgeRedirectUrl) {
    return (
      <KnowledgeFromConnectionEmbed
        redirectUrl={knowledgeRedirectUrl}
        onKnowledgeCreated={handleKnowledgeCreated}
      />
    );
  }

  return <div>Loading...</div>;
}

Message Events

The iframe will send various postMessage events to the parent window. All events follow this structure:
interface IFrameEvent {
  type: string;
  payload: any;
}

Available Event Types

Connection Events

datagrid-api/connection-created
Emitted when a new connection is successfully created. Used with the ConnectionEmbed component. Payload:
{
  object: "connection",
  id: string,
  name: string,
  teamspace_id: string,
  connector_id: string,
  valid: boolean,
  value: string,
  created_at: string,
  updated_at: string
}
datagrid-api/connection-updated
Emitted when an existing connection is successfully updated. Payload: Same as connection-created event.

Knowledge Events

datagrid-api/knowledge-created
Emitted when knowledge is successfully created from a connection. Used with the KnowledgeFromConnectionEmbed component. Payload:
{
  knowledge_id: string
}

Common Events

datagrid-api/error
Emitted when an error occurs during the connection or knowledge creation process. Payload:
{
  message: string,
  error: object | null
}
datagrid-api/resize
Emitted when the iframe needs to be resized to accommodate content. Payload:
{
  height: number,
  width: number
}
datagrid-api/content-loaded
Emitted when the iframe content has finished loading. Payload: null

Security Considerations

  • Always validate the origin of postMessage events to ensure they come from your expected domain
  • Implement proper error handling for all message types
  • Consider implementing a timeout mechanism for connection creation
  • Store connection credentials securely after successful creation

Best Practices

  1. Event Filtering: Always check that messages are from the expected source and contain the datagrid-api prefix
  2. Error Handling: Implement comprehensive error handling for all possible error scenarios
  3. User Feedback: Provide clear feedback to users about the connection status
  4. Responsive Design: Handle iframe resizing events to provide a smooth user experience
  5. Loading States: Show appropriate loading states while the iframe is initializing

Summary

ComponentAPI EndpointEvent on Success
ConnectionEmbedconnections.createConnectionRedirectUrl()datagrid-api/connection-created
KnowledgeFromConnectionEmbedknowledge.createKnowledgeFromConnection()datagrid-api/knowledge-created

Quick Reference

Creating a Connection:
// 1. Get redirect URL
const { redirect_url } = await datagridClient.connections.createConnectionRedirectUrl({
  connector_id: "google_drive",
});

// 2. Pass to ConnectionEmbed component
<ConnectionEmbed redirectUrl={redirect_url} onConnectionCreated={handleConnection} />
Creating Knowledge from Connection:
// 1. Get redirect URL (requires an existing connection_id)
const { redirect_url } = await datagridClient.knowledge.createKnowledgeFromConnection({
  connection_id: "conn_abc123",
});

// 2. Pass to KnowledgeFromConnectionEmbed component
<KnowledgeFromConnectionEmbed redirectUrl={redirect_url} onKnowledgeCreated={handleKnowledge} />