Passer au contenu principal
Firma vous permet d’ajouter des signatures électroniques juridiquement contraignantes à tout ce que vous construisez sur OpenAI. Utilisez le function calling de la Responses API pour permettre à vos agents IA d’envoyer des demandes de signature à la demande, connectez les serveurs MCP de Firma à la CLI Codex pour que l’IA génère du code d’intégration précis, ou ajoutez Firma comme connecteur ChatGPT pour gérer vos demandes de signature depuis l’application de bureau ChatGPT.

Prérequis

  • Un compte Firma avec une clé API
  • Une clé API OpenAI (pour le function calling), ou un compte ChatGPT Plus/Pro/Enterprise (pour la CLI Codex et les connecteurs)
  • Au moins un Modèle Firma avec des Champs de signature configurés
Firma utilise la clé API brute comme valeur de l’en-tête Authorization - ne la préfixez pas avec Bearer. Cela diffère de l’API OpenAI elle-même, qui utilise des jetons Bearer.

Pour commencer

Le function calling permet à un modèle GPT de décider quand appeler votre code. Vous déclarez une fonction que le modèle peut appeler, et lorsque l’utilisateur lui demande d’envoyer un contrat, le modèle renvoie un appel d’outil structuré que votre application exécute contre l’API Firma.Cette approche convient parfaitement aux agents IA, chatbots, et à toute application où une demande utilisateur en langage naturel doit se transformer en Demande de Signature.

Étape 1 : Stockez vos clés API

Conservez votre clé API OpenAI et votre clé API Firma dans des variables d’environnement. Ne les placez jamais dans du code frontend.
OPENAI_API_KEY=your_openai_key
FIRMA_API_KEY=your_firma_key

Étape 2 : Déclarez une fonction et gérez les appels d’outils

Avec la Responses API d’OpenAI (recommandée pour les nouveaux projets) :
import OpenAI from "openai";

const FIRMA_API = "https://api.firma.dev/functions/v1/signing-request-api";
const openai = new OpenAI();

const tools = [
  {
    type: "function",
    name: "send_signing_request",
    description:
      "Send a document for e-signature via Firma. Uses a pre-configured template and one signer.",
    parameters: {
      type: "object",
      properties: {
        name: {
          type: "string",
          description: "A descriptive name for the signing request.",
        },
        template_id: {
          type: "string",
          description: "The ID of the Firma template to send.",
        },
        signer_email: { type: "string" },
        signer_first_name: { type: "string" },
        signer_last_name: { type: "string" },
      },
      required: [
        "name",
        "template_id",
        "signer_email",
        "signer_first_name",
        "signer_last_name",
      ],
      additionalProperties: false,
    },
    strict: true,
  },
];

async function sendSigningRequest(args) {
  const response = await fetch(
    `${FIRMA_API}/signing-requests/create-and-send`,
    {
      method: "POST",
      headers: {
        Authorization: process.env.FIRMA_API_KEY,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        name: args.name,
        template_id: args.template_id,
        recipients: [
          {
            first_name: args.signer_first_name,
            last_name: args.signer_last_name,
            email: args.signer_email,
            designation: "Signer",
            order: 1,
          },
        ],
      }),
    }
  );

  const data = await response.json();
  if (!response.ok) return JSON.stringify({ error: data });

  return JSON.stringify({
    signing_request_id: data.id,
    status: "sent",
    signing_link: data.first_signer?.signing_link,
  });
}

export async function handleUserMessage(userText) {
  let input = [{ role: "user", content: userText }];

  let response = await openai.responses.create({
    model: "gpt-4.1",
    tools,
    input,
  });

  input.push(...response.output);

  for (const item of response.output) {
    if (item.type !== "function_call") continue;
    if (item.name === "send_signing_request") {
      const args = JSON.parse(item.arguments);
      const result = await sendSigningRequest(args);
      input.push({
        type: "function_call_output",
        call_id: item.call_id,
        output: result,
      });
    }
  }

  response = await openai.responses.create({
    model: "gpt-4.1",
    tools,
    input,
  });

  return { text: response.output_text };
}
Le endpoint create-and-send crée la Demande de Signature et l’envoie aux Destinataires en un seul appel API. Si vous voulez que le modèle rédige une demande pour révision avant l’envoi, utilisez POST /signing-requests pour créer un brouillon, puis POST /signing-requests/{id}/send une fois approuvé.

Étape 3 : Intégrez-le dans votre application

Appelez handleUserMessage depuis votre backend chaque fois que l’utilisateur envoie un message de chat :
app.post("/chat", async (req, res) => {
  const reply = await handleUserMessage(req.body.message);
  res.json(reply);
});
Un message utilisateur comme « Envoie le contrat de conseil à alice@acme.com » déclenchera l’appel de fonction.

Alternative Python

Le même flux avec le SDK Python :
import os
import json
import requests
from openai import OpenAI

FIRMA_API = "https://api.firma.dev/functions/v1/signing-request-api"
client = OpenAI()

tools = [
    {
        "type": "function",
        "name": "send_signing_request",
        "description": "Send a document for e-signature via Firma.",
        "parameters": {
            "type": "object",
            "properties": {
                "name": {"type": "string", "description": "A descriptive name for the signing request."},
                "template_id": {"type": "string"},
                "signer_email": {"type": "string"},
                "signer_first_name": {"type": "string"},
                "signer_last_name": {"type": "string"},
            },
            "required": [
                "name",
                "template_id",
                "signer_email",
                "signer_first_name",
                "signer_last_name",
            ],
            "additionalProperties": False,
        },
        "strict": True,
    },
]

def execute(args):
    r = requests.post(
        f"{FIRMA_API}/signing-requests/create-and-send",
        headers={
            "Authorization": os.environ["FIRMA_API_KEY"],
            "Content-Type": "application/json",
        },
        json={
            "name": args["name"],
            "template_id": args["template_id"],
            "recipients": [
                {
                    "first_name": args["signer_first_name"],
                    "last_name": args["signer_last_name"],
                    "email": args["signer_email"],
                    "designation": "Signer",
                    "order": 1,
                }
            ],
        },
    )
    return json.dumps(r.json())

input_list = [{"role": "user", "content": "Send the NDA to bob@example.com (Bob Smith)."}]

response = client.responses.create(
    model="gpt-4.1",
    tools=tools,
    input=input_list,
)

input_list += response.output

for item in response.output:
    if item.type == "function_call":
        args = json.loads(item.arguments)
        result = execute(args)
        input_list.append({
            "type": "function_call_output",
            "call_id": item.call_id,
            "output": result,
        })

response = client.responses.create(
    model="gpt-4.1",
    tools=tools,
    input=input_list,
)
print(response.output_text)

Intégration webhook

Pour suivre les événements de signature en temps réel, enregistrez un Webhook Firma pointant vers un endpoint de votre application :
app.post("/api/firma-webhook", async (req, res) => {
  const { type, data } = req.body;

  if (type === "signing_request.completed") {
    const signingRequestId = data.signing_request.id;
    // Update your DB, trigger downstream automation, etc.
  }

  res.json({ received: true });
});
Dans le tableau de bord Firma, sous Paramètres > Webhooks, enregistrez l’URL de votre endpoint. Firma envoie des événements pour tous les changements d’état majeurs. Consultez le guide des webhooks pour la liste complète des événements et la vérification de signature.
Vérifiez toujours la signature du webhook à l’aide de votre secret de signature de webhook Firma en production. Consultez le guide des webhooks pour les détails d’implémentation.

Signature intégrée

Pour les applications où les Signataires complètent les documents directement dans votre interface plutôt que d’ouvrir une page hébergée par Firma, la réponse de create-and-send inclut first_signer.id (le signing_request_user_id) et un first_signer.signing_link prêt à l’emploi. Chargez l’URL du Signataire dans une iframe :
<iframe
  src="https://app.firma.dev/signing/{signing_request_user_id}"
  style="width:100%;height:900px;border:0;"
  allow="camera;microphone;clipboard-write"
  title="Document Signing"
></iframe>
Consultez le guide de signature intégrée pour la configuration complète, y compris les bonnes pratiques de sécurité.

Astuces

  • Utilisez le function calling pour les agents en exécution, MCP pour la construction. Le function calling est ce que votre application déployée utilise pour envoyer des documents. Les serveurs MCP sont ce que vous et la CLI Codex utilisez pour construire cette intégration.
  • Passez template_id comme argument d’outil, pas comme chaîne libre. Les Modèles sont le moyen le plus sûr de limiter ce que le modèle peut envoyer.
  • Validez avant d’envoyer. Pour les documents à enjeux plus élevés, utilisez POST /signing-requests pour créer un brouillon, présentez-le à l’utilisateur, puis appelez POST /signing-requests/{id}/send seulement après leur confirmation.
  • Espaces de Travail pour les applications multi-tenant. Si vous construisez un produit SaaS au-dessus de l’API OpenAI, donnez à chaque client final son propre Espace de Travail Firma afin que les Modèles et l’utilisation restent isolés.

Prochaines étapes