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

# Supabase

> Añade firmas electrónicas legalmente vinculantes a cualquier aplicación de Supabase usando Edge Functions, Postgres y webhooks.

Añade firmas electrónicas legalmente vinculantes a cualquier aplicación de Supabase. Usa Supabase Edge Functions para llamar a la API de Firma, guarda el estado de la firma en tu base de datos Postgres y recibe actualizaciones en tiempo real mediante webhooks.

## Qué puedes construir

* **Flujos de firma de contratos** — activa Solicitudes de Firma cuando los usuarios completan un formulario o un pago
* **Paneles de estado de documentos** — controla qué documentos están pendientes, firmados o rechazados
* **Firma incrustada** — permite que los usuarios firmen documentos sin salir de tu app
* **Flujos de trabajo automatizados** — usa los webhooks de Firma junto con triggers de la base de datos de Supabase para iniciar acciones posteriores cuando se firman los documentos

## Requisitos previos

* Una [cuenta de Firma](https://app.firma.dev) con una clave API
* Un proyecto de Supabase con Edge Functions habilitadas
* La [CLI de Supabase](https://supabase.com/docs/guides/cli) instalada localmente

## Descripción general de la arquitectura

```text theme={null}
Your Frontend (React, Next.js, Flutter, etc.)
        │
        ▼
Supabase Edge Function ──► Firma API
        │                      │
        ▼                      │ (webhook)
Supabase Postgres  ◄──────────┘
  (signing_requests table)
```

Tu frontend llama a una Supabase Edge Function, que a su vez llama de forma segura a la API de Firma para crear Solicitudes de Firma. Cuando los destinatarios firman (o rechazan), Firma envía un webhook a otra Edge Function que actualiza tu base de datos.

## Paso 1: Guarda tu clave API de Firma

Añade tu clave API de Firma como un secreto de Supabase para que las Edge Functions puedan acceder a ella de forma segura:

```bash theme={null}
supabase secrets set FIRMA_API_KEY=your_api_key_here
```

## Paso 2: Crea una tabla para controlar las Solicitudes de Firma

Ejecuta este SQL en el Editor SQL de Supabase para crear una tabla que controle el estado de los documentos:

```sql theme={null}
create table signing_requests (
  id uuid primary key default gen_random_uuid(),
  firma_request_id text unique,
  user_id uuid references auth.users(id),
  template_id text,
  status text default 'pending',
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

-- Enable Row Level Security
alter table signing_requests enable row level security;

-- Users can only see their own signing requests
create policy "Users can view own requests"
  on signing_requests for select
  using (auth.uid() = user_id);
```

## Paso 3: Crea una Edge Function para enviar Solicitudes de Firma

Genera una nueva Edge Function:

```bash theme={null}
supabase functions new send-signing-request
```

Luego reemplaza el contenido de `supabase/functions/send-signing-request/index.ts`:

```typescript theme={null}
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

const corsHeaders = {
  "Access-Control-Allow-Origin": "*",
  "Access-Control-Allow-Headers": "authorization, content-type",
};

Deno.serve(async (req) => {
  if (req.method === "OPTIONS") {
    return new Response("ok", { headers: corsHeaders });
  }

  const supabase = createClient(
    Deno.env.get("SUPABASE_URL")!,
    Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
  );

  const { template_id, signer_email, signer_first_name, signer_last_name } =
    await req.json();

  // Get the authenticated user
  const authHeader = req.headers.get("Authorization")!;
  const {
    data: { user },
  } = await supabase.auth.getUser(authHeader.replace("Bearer ", ""));

  if (!user) {
    return new Response(JSON.stringify({ error: "Unauthorized" }), {
      status: 401,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }

  // Create a signing request via Firma API
  const firmaResponse = await fetch(
    "https://api.firma.dev/functions/v1/signing-request-api/signing-requests",
    {
      method: "POST",
      headers: {
        Authorization: Deno.env.get("FIRMA_API_KEY"),
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        template_id,
        recipients: [
          {
            first_name: signer_first_name,
            last_name: signer_last_name,
            email: signer_email,
            designation: "Signer",
            order: 1,
          },
        ],
      }),
    }
  );

  const firmaData = await firmaResponse.json();

  if (!firmaResponse.ok) {
    return new Response(JSON.stringify({ error: firmaData }), {
      status: firmaResponse.status,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }

  // Store the signing request in your database
  const { error } = await supabase.from("signing_requests").insert({
    firma_request_id: firmaData.id,
    user_id: user.id,
    template_id,
    status: "pending",
  });

  if (error) {
    return new Response(JSON.stringify({ error: error.message }), {
      status: 500,
      headers: { ...corsHeaders, "Content-Type": "application/json" },
    });
  }

  return new Response(JSON.stringify(firmaData), {
    status: 201,
    headers: { ...corsHeaders, "Content-Type": "application/json" },
  });
});
```

Despliégala:

```bash theme={null}
supabase functions deploy send-signing-request
```

## Paso 4: Gestiona los webhooks de Firma

Crea otra Edge Function para recibir eventos de webhook de Firma cuando los documentos se firman, se rechazan o se actualizan:

```bash theme={null}
supabase functions new firma-webhook
```

Reemplaza el contenido de `supabase/functions/firma-webhook/index.ts`:

```typescript theme={null}
import { createClient } from "https://esm.sh/@supabase/supabase-js@2";

Deno.serve(async (req) => {
  const supabase = createClient(
    Deno.env.get("SUPABASE_URL")!,
    Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
  );

  const payload = await req.json();
  const { type, data } = payload;

  // Map Firma event types to a simple status
  const statusMap: Record<string, string> = {
    "signing_request.completed": "completed",
    "signing_request.cancelled": "cancelled",
    "signing_request.expired": "expired",
    "signing_request.sent": "sent",
    "signing_request.recipient.signed": "recipient_signed",
    "signing_request.recipient.declined": "declined",
  };

  const status = statusMap[type];
  if (!status) {
    // Event type we don't need to track
    return new Response(JSON.stringify({ received: true }), { status: 200 });
  }

  // The signing request ID is nested inside data.signing_request
  const signingRequestId = data.signing_request?.id;
  if (!signingRequestId) {
    return new Response(JSON.stringify({ error: "Missing signing request ID" }), {
      status: 400,
    });
  }

  const { error } = await supabase
    .from("signing_requests")
    .update({
      status,
      updated_at: new Date().toISOString(),
    })
    .eq("firma_request_id", signingRequestId);

  if (error) {
    return new Response(JSON.stringify({ error: error.message }), {
      status: 500,
    });
  }

  return new Response(JSON.stringify({ received: true }), { status: 200 });
});
```

Despliégala y hazla accesible públicamente (los webhooks no envían encabezados de autenticación):

```bash theme={null}
supabase functions deploy firma-webhook --no-verify-jwt
```

Luego registra la URL del webhook en tu panel de Firma, en **Configuración → Webhooks**. La URL de tu endpoint será:

```text theme={null}
https://<your-project-ref>.supabase.co/functions/v1/firma-webhook
```

<Warning>
  Para uso en producción, verifica la firma del webhook usando tu secreto de firma de webhooks de Firma. Consulta la [guía de webhooks](/es/guides/webhooks) para más detalles sobre la verificación de firmas.
</Warning>

## Paso 5: Incrusta la experiencia de firma (opcional)

Para una experiencia de firma dentro de la app, usa el componente de [firma incrustada](/es/guides/embeddable-signing) de Firma. Una vez que tengas el `signing_request_user_id` de la respuesta de la API, cárgalo en un iframe:

```html theme={null}
<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>
```

Consulta la [guía de firma incrustada](/es/guides/embeddable-signing) para las instrucciones de configuración completas, incluidas las prácticas recomendadas de seguridad.

## Paso 6: Consulta el estado de la firma desde tu frontend

Con Row Level Security habilitado, tu frontend puede consultar el estado de la firma directamente:

```typescript theme={null}
const { data: requests } = await supabase
  .from("signing_requests")
  .select("*")
  .order("created_at", { ascending: false });
```

## Próximos pasos

* [Referencia de la API de Firma](/api-reference) — documentación completa de los endpoints
* [Guía de webhooks](/es/guides/webhooks) — tipos de eventos y verificación de firmas
* [Firma incrustada](/es/guides/embeddable-signing) — experiencia de firma dentro de la app
* [White-labeling](/es/guides/white-labeling) — personaliza correos y marca
* [Creación de espacios de trabajo](/es/guides/creating-workspaces) — configuraciones multiusuario para aplicaciones SaaS
