> ## 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.

# Salesforce

> Agrega firmas electrónicas legalmente vinculantes a cualquier org de Salesforce usando Flow, Apex o Agentforce.

Agrega firmas electrónicas legalmente vinculantes a cualquier org de Salesforce usando Flow, Apex o Agentforce. Envía solicitudes de firma a partir de una actualización de registro, incrusta la firma en Lightning y enruta los eventos de webhook de vuelta a los registros de Salesforce.

Esta guía cubre tres caminos de integración:

1. **Flow con External Services** — Sin código. Registra la especificación OpenAPI de Firma una vez y luego invoca `Create and send signing request` desde cualquier Flow. Ideal para administradores.
2. **Apex con Named Credentials** — Con código. Llama a Firma directamente desde clases Apex, Flow Actions o controladores LWC. Ideal para desarrolladores que quieren control total.
3. **Acción de Agentforce** — Expón Firma como una Action en un agente de Agentforce para que pueda enviar solicitudes de firma en respuesta a un prompt de usuario o a un disparador.

Los tres caminos comparten la misma Named Credential, así que configúrala primero.

## Requisitos previos

* Una [cuenta de Firma](https://app.firma.dev) con una clave API
* Una org de Salesforce (edición Enterprise, Unlimited o Developer) con permiso para crear Named Credentials y External Services
* Al menos una plantilla de Firma con campos de firma configurados

<Note>
  Firma usa la clave API en bruto como el valor del header `Authorization`. No la prefijes con `Bearer`. Esto difiere de muchas otras APIs.
</Note>

## Paso 0: Guardar la clave API de Firma como una Named Credential

Las Named Credentials son el patrón seguro de Salesforce para guardar URLs de endpoints y headers de autenticación. El resto de las secciones de esta guía la referencian.

1. En Setup, busca **Named Credentials** y abre la página
2. En **External Credentials**, haz clic en **New**:
   * Label: `Firma`
   * Name: `Firma`
   * Authentication Protocol: `Custom`
3. Entra a la nueva External Credential, baja hasta **Principals** y haz clic en **New**:
   * Parameter Name: `Default`
   * Sequence Number: `1`
   * Identity Type: `Named Principal`
   * Authentication Parameters: agrega un parámetro
     * Name: `ApiKey`
     * Value: tu clave API de Firma
4. Baja hasta **Custom Headers** y agrega uno:
   * Name: `Authorization`
   * Value: `{!$Credential.Firma.ApiKey}`
5. De vuelta en **Named Credentials**, haz clic en **New**:
   * Label: `Firma API`
   * Name: `Firma_API`
   * URL: `https://api.firma.dev/functions/v1/signing-request-api`
   * External Credential: `Firma`
   * Allowed Namespaces: deja el valor predeterminado
6. Guarda

<Warning>
  Nunca escribas la clave API directamente en Apex, Flow o un Custom Setting. Siempre referénciala a través de la Named Credential para que permanezca cifrada en reposo y la rotación solo requiera editar un registro.
</Warning>

## Camino 1: Flow con External Services

El camino sin código. Importas la especificación OpenAPI de Firma una vez y las acciones quedan disponibles como pasos invocables en cualquier Flow.

### Paso 1: Registrar Firma como un External Service

1. En Setup, busca **External Services** y haz clic en **Add an External Service**
2. Elige **From API Specification** y luego **Save and Next**
3. Configura:
   * External Service Name: `Firma`
   * Select a Named Credential: `Firma_API`
   * Service Schema: `Upload from Local` o pega el JSON
4. Pega la especificación OpenAPI de Firma desde `https://docs.firma.dev/api-reference/v01.26.00/openapi-v01.26.00.json`
5. Haz clic en **Save and Next**
6. Selecciona las operaciones que quieres disponibles en Flow. Opciones comunes:
   * `POST /signing-requests/create-and-send`
   * `POST /signing-requests`
   * `POST /signing-requests/{id}/send`
   * `GET /signing-requests/{id}`
   * `GET /templates`
7. Haz clic en **Save and Next** y luego en **Finish**

<Note>
  Consulta el [changelog de la API de Firma](/es/guides/api-changelog) para conocer la URL más reciente de la especificación. Salesforce guarda en caché la especificación en el momento del registro, así que vuelve a registrar el External Service cada vez que quieras nuevos endpoints.
</Note>

### Paso 2: Construir el Flow

1. En Setup, abre **Flows** y crea un nuevo Flow (Record-Triggered es lo más común)
2. Elige el objeto disparador (Opportunity, Contract, Quote o un objeto personalizado) y la condición que debe enviar una solicitud de firma (por ejemplo, `StageName` es igual a `Closed Won`)
3. Agrega un elemento **Action**
4. Busca `Firma` y elige `Create and send signing request`
5. Mapea las entradas:
   * `template_id`: un valor de Custom Metadata, un campo del registro o un ID de plantilla fijo
   * `recipients`: construye una colección de registros de destinatarios. Los campos obligatorios son `first_name` y `email`. Los campos opcionales incluyen `last_name`, `designation` (por defecto `Signer`), `order`, `company`, `title`, `phone_number` y campos de dirección. La forma más fácil es un elemento **Assignment** que construya la colección a partir de los campos de contacto del registro disparador
6. Guarda y activa

Cuando se dispara el trigger, Salesforce llama a Firma a través de la Named Credential y Firma envía el documento al firmante.

## Camino 2: Apex con Named Credentials

Para desarrolladores que quieren control total, llama a Firma directamente desde Apex. Usa la Named Credential como base del endpoint para que la clave API permanezca cifrada.

```java theme={null}
public with sharing class FirmaService {

    private static final String FIRMA_BASE = 'callout:Firma_API';

    public class Recipient {
        public String first_name;
        public String last_name;
        public String email;
        public String designation;
        public Integer order;
    }

    public static String createAndSend(String templateId, Recipient signer) {
        signer.designation = 'Signer';
        signer.order = 1;

        Map<String, Object> body = new Map<String, Object>{
            'template_id' => templateId,
            'recipients' => new List<Recipient>{ signer }
        };

        HttpRequest req = new HttpRequest();
        req.setEndpoint(FIRMA_BASE + '/signing-requests/create-and-send');
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setBody(JSON.serialize(body));

        Http http = new Http();
        HttpResponse res = http.send(req);

        if (res.getStatusCode() >= 300) {
            throw new CalloutException('Firma error: ' + res.getBody());
        }

        Map<String, Object> data =
            (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
        return (String) data.get('id');
    }
}
```

El prefijo `callout:Firma_API` le indica a Salesforce que use la Named Credential, la cual inyecta el header `Authorization` automáticamente. Ninguna clave API aparece en el código, en los logs ni en la inspección de solicitudes serializadas.

<Note>
  El endpoint `create-and-send` crea la solicitud de firma y la envía por correo a los destinatarios en una sola llamada. Si necesitas un paso de revisión controlado por Apex, usa `POST /signing-requests` para crear un borrador y luego `POST /signing-requests/{id}/send` por separado.
</Note>

Expón el método Apex como una Invocable Action para que Flow pueda llamarlo:

```java theme={null}
public with sharing class FirmaInvocable {

    public class Input {
        @InvocableVariable(required=true) public String templateId;
        @InvocableVariable(required=true) public String firstName;
        @InvocableVariable(required=true) public String lastName;
        @InvocableVariable(required=true) public String email;
    }

    public class Output {
        @InvocableVariable public String signingRequestId;
    }

    @InvocableMethod(label='Send Firma signing request')
    public static List<Output> send(List<Input> inputs) {
        List<Output> results = new List<Output>();
        for (Input i : inputs) {
            FirmaService.Recipient r = new FirmaService.Recipient();
            r.first_name = i.firstName;
            r.last_name = i.lastName;
            r.email = i.email;
            String id = FirmaService.createAndSend(i.templateId, r);
            Output o = new Output();
            o.signingRequestId = id;
            results.add(o);
        }
        return results;
    }
}
```

## Camino 3: Acción de Agentforce

Para permitir que un agente de Agentforce envíe solicitudes de firma en respuesta a un prompt ("envía el NDA estándar a [alice@example.com](mailto:alice@example.com)"), envuelve una de las opciones anteriores como una Agent Action.

1. En Setup, abre **Agentforce Builder** y elige el agente que quieres extender
2. Abre el **Topic** correspondiente (por ejemplo, `Contract Lifecycle`)
3. Haz clic en **New Action** y elige **Flow** o **Apex**
   * **Flow**: elige un screen Flow o un Flow autolanzado que envuelva la acción `Firma.Create and send signing request` de External Services
   * **Apex**: elige el método `FirmaInvocable.send`
4. Define las entradas que el agente recopilará de la conversación: plantilla, nombre del firmante, correo del firmante
5. Agrega la acción al Topic y publica

<Warning>
  Usa el prompt de confirmación de Agentforce antes de cualquier acción de envío para que el agente lea en voz alta el nombre de la plantilla y los datos del firmante antes de activar Firma. Las solicitudes de firma salientes llegan a terceros; un paso de confirmación vale el turno extra.
</Warning>

## Integración de webhooks: reaccionar cuando se firman documentos

Recibe webhooks de Firma en Salesforce exponiendo un endpoint Apex REST, y luego actualiza el registro de origen (Opportunity, Contract, objeto personalizado) cuando la solicitud de firma se completa.

### Paso 1: Crear el endpoint Apex REST

```java theme={null}
@RestResource(urlMapping='/firma-webhook')
global with sharing class FirmaWebhook {

    @HttpPost
    global static void receive() {
        RestRequest req = RestContext.request;
        Map<String, Object> payload =
            (Map<String, Object>) JSON.deserializeUntyped(
                req.requestBody.toString()
            );

        String eventType = (String) payload.get('type');
        Map<String, Object> data =
            (Map<String, Object>) payload.get('data');

        if (eventType == 'signing_request.completed') {
            Map<String, Object> sr =
                (Map<String, Object>) data.get('signing_request');
            String signingRequestId = (String) sr.get('id');

            List<Opportunity> opps = [
                SELECT Id FROM Opportunity
                WHERE Firma_Signing_Request_Id__c = :signingRequestId
                LIMIT 1
            ];
            if (!opps.isEmpty()) {
                opps[0].StageName = 'Signed';
                update opps[0];
            }
        }

        RestContext.response.statusCode = 200;
    }
}
```

### Paso 2: Verificar la firma del webhook

Firma firma cada payload de webhook con HMAC-SHA256. Verifica siempre la firma en producción para rechazar payloads falsificados. Tu webhook secret está disponible en **Configuración > Webhooks** en el panel de Firma.

```java theme={null}
private static Boolean verifySignature(
    String payload, String signatureHeader, String secret
) {
    Blob hmac = Crypto.generateMac(
        'HmacSHA256',
        Blob.valueOf(payload),
        Blob.valueOf(secret)
    );
    String expected = EncodingUtil.convertToHex(hmac);
    return expected.equalsIgnoreCase(signatureHeader);
}
```

Llama a esto al inicio del método `receive()` antes de procesar:

```java theme={null}
String signature = RestContext.request.headers.get('x-firma-signature');
String body = RestContext.request.requestBody.toString();
String secret = '{!$Credential.Firma_Webhook.Secret}'; // o un valor de Custom Metadata

if (!verifySignature(body, signature, secret)) {
    RestContext.response.statusCode = 401;
    return;
}
```

### Paso 3: Exponer el endpoint públicamente

Las llamadas de webhook de Firma no están autenticadas como un usuario de Salesforce, así que expón el endpoint a través de un **Experience Cloud Site**. Crea un site (o usa uno existente) y luego otorga al perfil de guest user del site permiso para ejecutar la clase Apex `FirmaWebhook`. Consulta [Salesforce: Allow Guest Users to Access Apex REST](https://help.salesforce.com/s/articleView?id=sf.networks_guest_user_access_apex_rest.htm) para conocer los pasos de configuración completos.

### Paso 4: Registrar el webhook en Firma

1. En el panel de Firma, ve a **Configuración > Webhooks**
2. Agrega un nuevo webhook apuntando a `https://<your-site-domain>/services/apexrest/firma-webhook`
3. Suscríbete a los eventos que te interesan (`signing_request.completed`, `signing_request.recipient.declined`, `signing_request.expired`)

Consulta la [guía de webhooks](/es/guides/webhooks) para conocer todos los tipos de eventos y formas de payload.

## Firma incrustada en Lightning

Si quieres que los firmantes completen documentos dentro de una página Lightning, usa un Lightning Web Component que incruste la interfaz de firma de Firma. Después de una llamada create-and-send exitosa, lee el ID del firmante de la respuesta y pásalo al LWC:

```html theme={null}
<template>
  <iframe
    src={signingUrl}
    style="width:100%;height:900px;border:0;"
    allow="camera;microphone;clipboard-write"
    title="Document Signing"
  ></iframe>
</template>
```

```javascript theme={null}
import { LightningElement, api } from 'lwc';

export default class FirmaSigning extends LightningElement {
  @api signingRequestUserId;

  get signingUrl() {
    return `https://app.firma.dev/signing/${this.signingRequestUserId}`;
  }
}
```

Agrega `https://app.firma.dev` a tus CSP Trusted Sites para que el iframe cargue. Consulta la [guía de firma incrustada](/es/guides/embeddable-signing) para conocer la configuración completa, incluidas las mejores prácticas de seguridad.

## Para ISVs y partners de AppExchange: firma multi-org

Si estás construyendo una app de AppExchange que necesita firmas electrónicas para cada una de las orgs de tus clientes, usa [Firma Customer Workspaces](/es/guides/creating-workspaces). Cada org de cliente obtiene su propio espacio de trabajo de Firma aislado con plantillas separadas, seguimiento de uso y registro de auditoría. Aprovisiona un espacio de trabajo por org en el momento de la instalación, guarda la clave API del espacio de trabajo en un Protected Custom Setting en esa org y referéncialo desde la Named Credential. Sin fuga de datos entre clientes.

## Conexión MCP para construcción asistida por IA

Firma ofrece un [servidor Docs MCP](/es/guides/mcp) en `https://docs.firma.dev/mcp`. Conéctalo a Claude, Cursor o cualquier herramienta de IA compatible con MCP mientras escribes Apex o construyes Flows, y el asistente podrá responder preguntas precisas sobre la API a partir de la documentación de Firma. Esto es para la experiencia de construcción y no afecta tu integración desplegada.

## Próximos pasos

* [Autenticación de la API](/es/guides/authentication) - Claves API y alcance de espacios de trabajo
* [Guía de webhooks](/es/guides/webhooks) - Tipos de eventos, payloads y verificación de firma
* [Firma incrustada](/es/guides/embeddable-signing) - Experiencia de firma dentro de la app
* [Creación de espacios de trabajo](/es/guides/creating-workspaces) - Configuraciones multi-tenant para apps SaaS
* [Guía de configuración completa](/es/guides/complete-setup-guide) - Recorrido de integración de Firma de extremo a extremo
* [Referencia de la API](/api-reference) - Documentación completa de endpoints
