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

# Autenticación de API y tokens JWT

> Aprende a autenticar solicitudes de API con claves API y a usar tokens JWT para los editores incrustados de plantillas y solicitudes de firma

# Autenticación de API y tokens JWT

La API de Firma utiliza dos métodos de autenticación: autenticación con clave API para solicitudes de servidor a servidor, y tokens JWT para incrustar los editores de plantillas y de solicitudes de firma en tu aplicación.

## Autenticación con clave API

Todos los endpoints de la API requieren autenticación mediante una clave API en el encabezado `Authorization`.

### Cómo funciona

Tu clave API autentica tus solicitudes y determina a qué recursos del espacio de trabajo puedes acceder. Cada espacio de trabajo tiene su propia clave API única, que puedes obtener a través del endpoint [Get Workspace](/api-reference/v01.15.00/workspaces/get-a-workspace).

**Espacio de trabajo protegido**: cada cuenta de empresa tiene un espacio de trabajo protegido que no se puede eliminar. Este espacio de trabajo protegido contiene la clave API principal de tu cuenta, la cual tiene acceso a todos los endpoints de espacios de trabajo, claves API, empresa/cuenta y webhooks. Usa esta clave para operaciones a nivel de cuenta o cuando necesites gestionar varios espacios de trabajo.

### Modo de prueba (claves live vs. test)

Cada espacio de trabajo tiene **dos** claves API: una clave **live** y una clave **test**. El modo de prueba se determina según la clave que envíes; no existe un indicador o parámetro independiente.

* Las solicitudes autenticadas con la clave **test** **no** consumen créditos, y cualquier solicitud de firma que creen se marca como de prueba y lleva marca de agua.
* Las solicitudes autenticadas con la clave **live** se ejecutan normalmente y consumen créditos.

Ambas claves se devuelven al crear un espacio de trabajo (`api_key` = live, `test_api_key` = test) y mediante los endpoints [Get Workspace](/api-reference/v01.24.00/workspaces/get-a-workspace) y List Workspaces. Usa la clave test mientras integras y luego cambia a la clave live para producción.

Puedes rotar cada tipo de clave de forma independiente: pasa `key_type` (`"live"` o `"test"`, por defecto `"live"`) a los endpoints de [regenerar](/api-reference/v01.24.00/workspaces/regenerate-workspace-api-key) y [expirar](/api-reference/v01.24.00/workspaces/expire-pending-api-keys). Rotar un tipo no afecta al otro.

<Note>
  Las claves test son credenciales completas con el mismo alcance de acceso que las claves live; guárdalas en el servidor y nunca las expongas en código de cliente. La única diferencia está en el comportamiento de facturación y marca de agua.
</Note>

### Rotación de claves API

Puedes regenerar claves API para espacios de trabajo no protegidos para mejorar la seguridad. Al regenerar una clave:

1. **Se crea inmediatamente una nueva clave API** y se devuelve en la respuesta
2. **Las claves antiguas se marcan para expirar en 24 horas**: siguen funcionando durante este periodo de gracia
3. **Puedes expirar manualmente las claves antiguas antes de tiempo** una vez que hayas verificado que la nueva clave funciona

<Note>
  **Las claves de espacios de trabajo protegidos no se pueden regenerar** mediante la API. Esto evita bloqueos accidentales de tu cuenta. Contacta con soporte si necesitas rotar la clave de tu espacio de trabajo protegido.
</Note>

#### Regenerar clave API

Genera una nueva clave API para un espacio de trabajo. La clave antigua expirará automáticamente después de 24 horas:

```javascript theme={null}
const response = await fetch(
  `https://api.firma.dev/functions/v1/signing-request-api/workspaces/${workspaceId}/api-key/regenerate`,
  {
    method: 'POST',
    headers: {
      'Authorization': process.env.FIRMA_API_KEY,
      'Content-Type': 'application/json'
    }
  }
);

const result = await response.json();
console.log('New API key:', result.new_key);
// Store the new key securely
```

**Respuesta:**

```json theme={null}
{
  "message": "API key regenerated. Old keys will expire in 24 hours.",
  "workspace_id": "123e4567-e89b-12d3-a456-426614174000",
  "new_key": "firma_api_abc123xyz...",
  "expiring_keys": [
    {
      "id": "old-key-uuid",
      "expires_at": "2025-12-19T10:30:00Z"
    }
  ]
}
```

#### Expirar claves antiguas antes de tiempo

Después de verificar que tu nueva clave funciona, puedes expirar inmediatamente todas las claves pendientes:

```javascript theme={null}
const response = await fetch(
  `https://api.firma.dev/functions/v1/signing-request-api/workspaces/${workspaceId}/api-key/expire`,
  {
    method: 'POST',
    headers: {
      'Authorization': process.env.FIRMA_API_KEY,
      'Content-Type': 'application/json'
    }
  }
);

const result = await response.json();
console.log(`Expired ${result.expired_count} key(s)`);
```

**Respuesta:**

```json theme={null}
{
  "message": "Expired 1 pending API key(s)",
  "workspace_id": "123e4567-e89b-12d3-a456-426614174000",
  "expired_count": 1,
  "expired_keys": ["old-key-uuid"]
}
```

**Buenas prácticas para la rotación de claves:**

1. Llama al endpoint de regeneración para obtener una nueva clave
2. Actualiza la configuración de tu aplicación con la nueva clave
3. Comprueba que la nueva clave funciona correctamente
4. Llama al endpoint de expiración para invalidar inmediatamente las claves antiguas
5. Monitorea si hay errores que indiquen que algún servicio todavía usa la clave antigua

<Warning>
  **Nunca expongas tu clave API en código frontend ni en aplicaciones del lado del cliente.** Las claves API solo deben usarse en servicios backend seguros. Guárdalas siempre como variables de entorno.
</Warning>

### Formato del encabezado

La clave API se puede enviar de dos formas:

1. **Formato directo** (recomendado por su simplicidad):

```bash theme={null}
Authorization: your-api-key-here
```

2. **Formato Bearer token** (opcional):

```bash theme={null}
Authorization: Bearer your-api-key-here
```

Ambos formatos son válidos. El prefijo Bearer es opcional pero no obligatorio.

### Ejemplos de código

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.firma.dev/functions/v1/signing-request-api/templates \
    -H "Authorization: YOUR_API_KEY" \
    -H "Content-Type: application/json"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    'https://api.firma.dev/functions/v1/signing-request-api/templates',
    {
      headers: {
        'Authorization': process.env.FIRMA_API_KEY,
        'Content-Type': 'application/json'
      }
    }
  );

  const templates = await response.json();
  ```

  ```python Python theme={null}
  import os
  import requests

  headers = {
      'Authorization': os.environ['FIRMA_API_KEY'],
      'Content-Type': 'application/json'
  }

  response = requests.get(
      'https://api.firma.dev/functions/v1/signing-request-api/templates',
      headers=headers
  )

  templates = response.json()
  ```
</CodeGroup>

### Respuesta de error

Si tu clave API falta o es inválida, recibirás una respuesta `401 Unauthorized`:

```json theme={null}
{
  "error": "Unauthorized",
  "code": "UNAUTHORIZED",
  "message": "Invalid or missing API key"
}
```

***

## Tokens JWT para funciones incrustadas

Los tokens JWT (JSON Web Token) te permiten incrustar el editor de plantillas y el editor de solicitudes de firma de Firma directamente en tu aplicación. Estos tokens están firmados con RSA-256 y tienen un tiempo de vida limitado por seguridad.

### Cuándo usar tokens JWT

Usa tokens JWT cuando quieras:

* Incrustar el editor de plantillas en tu aplicación para que los usuarios creen o editen plantillas de documentos
* Incrustar el editor de solicitudes de firma para que los usuarios personalicen documentos antes de enviarlos
* Proporcionar acceso seguro y de tiempo limitado a plantillas o solicitudes de firma específicas
* Controlar a qué recursos pueden acceder los usuarios sin exponer tu clave API

<Note>
  **Los tokens JWT siempre deben generarse desde tu backend seguro**, nunca desde código frontend. Tu backend usa la clave API para generar los tokens, que luego se pasan al frontend para inicializar el editor.
</Note>

### Tipos de token JWT

| Tipo de token                   | Endpoint                                                                                                                         | Expiración | Caso de uso                                                              |
| ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------ |
| **Token de plantilla**          | [Generate JWT Token for Embedding Templates](/api-reference/v01.15.00/jwt-management/generate-jwt-token-for-embedding-templates) | 24 horas   | Incrustar el editor de plantillas para crear/editar plantillas           |
| **Token de solicitud de firma** | [Generate JWT Token for Signing Request](/api-reference/v01.15.00/jwt-management/generate-jwt-token-for-signing-request)         | 24 horas   | Incrustar el editor de solicitudes de firma para personalizar documentos |

### Flujo de autenticación

Así es como funciona la autenticación JWT para funciones incrustadas:

```mermaid theme={null}
sequenceDiagram
    participant User as User Browser
    participant Backend as Your Backend
    participant Firma as Firma API
    participant Editor as Embedded Editor

    User->>Backend: Request to edit template
    Backend->>Firma: POST /generate-template-token<br/>(with API key)
    Firma->>Backend: JWT token (24h expiry)
    Backend->>User: Return JWT token
    User->>Editor: Initialize editor with JWT
    Editor->>Firma: Authenticate with JWT
    Firma->>Editor: Grant access to template
    Editor->>User: Display editor interface
```

### Guía de implementación

#### Paso 1: Generar el token JWT (backend)

Genera un token JWT desde tu backend seguro usando tu clave API:

<CodeGroup>
  ```javascript Node.js/Express theme={null}
  // Backend endpoint to generate JWT for template editing
  app.post('/api/get-template-token', async (req, res) => {
    const { templateId } = req.body;

    try {
      const response = await fetch(
        'https://api.firma.dev/functions/v1/signing-request-api/generate-template-token',
        {
          method: 'POST',
          headers: {
            'Authorization': process.env.FIRMA_API_KEY,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            companies_workspaces_templates_id: templateId
          })
        }
      );

      const data = await response.json();
      
      // Return JWT to frontend (never expose API key)
      res.json({ 
        token: data.jwt,
        expiresAt: data.expires_at 
      });
    } catch (error) {
      res.status(500).json({ error: 'Failed to generate token' });
    }
  });
  ```

  ```python Python/Flask theme={null}
  from flask import Flask, request, jsonify
  import os
  import requests

  app = Flask(__name__)

  @app.route('/api/get-template-token', methods=['POST'])
  def get_template_token():
      template_id = request.json.get('templateId')
      
      try:
          response = requests.post(
              'https://api.firma.dev/functions/v1/signing-request-api/generate-template-token',
              headers={
                  'Authorization': os.environ['FIRMA_API_KEY'],
                  'Content-Type': 'application/json'
              },
              json={
                  'companies_workspaces_templates_id': template_id
              }
          )
          
          data = response.json()
          
          # Return JWT to frontend (never expose API key)
          return jsonify({
              'token': data['jwt'],
              'expiresAt': data['expires_at']
          })
      except Exception as e:
          return jsonify({'error': 'Failed to generate token'}), 500
  ```
</CodeGroup>

**Respuesta:**

```json theme={null}
{
  "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "jwt_id": "a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6",
  "expires_at": "2025-12-18T10:00:00Z",
  "template_id": "template-uuid-here"
}
```

#### Paso 2: Inicializar el editor (frontend)

Usa el token JWT para inicializar el editor incrustado en tu frontend:

```html theme={null}
<!DOCTYPE html>
<html>
<head>
  <title>Template Editor</title>
  <!-- Load the Firma Template Editor library -->
  <script src="https://api.firma.dev/functions/v1/embed-proxy/template-editor.js"></script>
</head>
<body>
  <div id="firma-editor-container" style="width: 100%; height: 600px;"></div>

  <script>
    async function initializeEditor(templateId) {
      // Request JWT from your backend
      const response = await fetch('/api/get-template-token', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ templateId })
      });

      const { token, expiresAt } = await response.json();

      // Initialize the embedded editor
      window.FirmaTemplateEditor.init({
        container: '#firma-editor-container',
        jwt: token,
        templateId: templateId,
        theme: 'light', // or 'dark'
        readOnly: false,
        onSave: (savedData) => {
          console.log('Template saved successfully:', savedData);
        },
        onError: (error) => {
          console.error('Editor error:', error);
        },
        onLoad: (template) => {
          console.log('Template loaded:', template);
        }
      });
    }

    // Initialize with your template ID
    initializeEditor('your-template-id-here');
  </script>
</body>
</html>
```

Para el editor de solicitudes de firma, usa el endpoint JWT de solicitudes de firma y la librería del editor de solicitudes de firma:

```javascript theme={null}
// Generate signing request token from backend
const response = await fetch('/api/get-signing-request-token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ signingRequestId })
});

const { token } = await response.json();

// Load signing request editor library
// <script src="https://api.firma.dev/functions/v1/embed-proxy/signing-request-editor.js"></script>

// Initialize signing request editor
window.FirmaSigningRequestEditor.init({
  container: '#firma-signing-request-container',
  jwt: token,
  signingRequestId: signingRequestId,
  theme: 'light',
  onSave: (data) => console.log('Signing request saved:', data),
  onSend: (data) => console.log('Signing request sent:', data),
  onError: (error) => console.error('Error:', error)
});
```

#### Paso 3: Revocar el token JWT (opcional)

Revoca un token JWT cuando ya no sea necesario:

<CodeGroup>
  ```javascript Node.js theme={null}
  const response = await fetch(
    'https://api.firma.dev/functions/v1/signing-request-api/revoke-template-token',
    {
      method: 'POST',
      headers: {
        'Authorization': process.env.FIRMA_API_KEY,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        jwt_id: 'a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6'
      })
    }
  );

  const result = await response.json();
  // { message: "JWT revoked successfully", jwt_id: "...", revoked_at: "..." }
  ```

  ```python Python theme={null}
  response = requests.post(
      'https://api.firma.dev/functions/v1/signing-request-api/revoke-template-token',
      headers={
          'Authorization': os.environ['FIRMA_API_KEY'],
          'Content-Type': 'application/json'
      },
      json={
          'jwt_id': 'a1b2c3d4-e5f6-7g8h-9i0j-k1l2m3n4o5p6'
      }
  )

  result = response.json()
  ```
</CodeGroup>

### Buenas prácticas de seguridad para JWT

<Warning>
  **Lista de comprobación de seguridad:**

  1. ✅ **Genera siempre los JWT desde tu backend**: nunca expongas tu clave API en código frontend
  2. ✅ **Usa variables de entorno**: guarda las claves API de forma segura, nunca las escribas de forma fija en el código
  3. ✅ **Valida la expiración del token**: comprueba `expires_at` y renueva los tokens según sea necesario
  4. ✅ **Usa solo HTTPS**: nunca transmitas tokens por conexiones sin cifrar
  5. ✅ **Revoca los tokens que no uses**: revoca los JWT cuando la edición haya terminado o la sesión finalice
  6. ✅ **Implementa la renovación de tokens**: solicita nuevos tokens antes de que expiren para sesiones prolongadas
  7. ✅ **Limita el alcance de los tokens de forma adecuada**: cada JWT está vinculado a una plantilla o solicitud de firma específica
</Warning>

***

##

***

## Guías relacionadas

Aprende más sobre cómo implementar funciones incrustadas y trabajar con la API:

* [Embeddable Template Editor](/es/guides/embeddable-template-editor) - Guía completa para incrustar el editor de plantillas
* [Embeddable Signing Request Editor](/es/guides/embeddable-signing-request-editor) - Incrusta la personalización de solicitudes de firma
* [Sending Signing Requests](/es/guides/sending-signing-request) - Envía documentos para su firma
* [Webhooks](/es/guides/webhooks) - Suscríbete a eventos en tiempo real

## Referencia de la API

Endpoints clave de gestión de autenticación y JWT:

**Gestión de claves API:**

* [Get Workspace](/api-reference/v01.15.00/workspaces/get-a-workspace) - Recupera la clave API del espacio de trabajo
* [Regenerate Workspace API Key](/api-reference/v01.15.00/workspaces/regenerate-workspace-api-key) - Genera una nueva clave API
* [Expire Pending API Keys](/api-reference/v01.15.00/workspaces/expire-pending-api-keys) - Expira inmediatamente las claves antiguas

**Gestión de tokens JWT:**

* [Generate JWT Token for Embedding Templates](/api-reference/v01.15.00/jwt-management/generate-jwt-token-for-embedding-templates)
* [Generate JWT Token for Signing Request](/api-reference/v01.15.00/jwt-management/generate-jwt-token-for-signing-request)
* [Revoke Template JWT Token](/api-reference/v01.15.00/jwt-management/revoke-template-jwt-token)
* [Revoke Signing Request JWT Token](/api-reference/v01.15.00/jwt-management/revoke-a-signing-request-jwt-token)

**Primeros pasos:**

* [Get Company Information](/api-reference/v01.15.00/company/get-company-information)
* [Create Template](/api-reference/v01.15.00/templates/create-template)
* [Create Signing Request](/api-reference/v01.15.00/signing-requests/create-signing-request)
