---
title: "Derechos ARCO vía API"
description: "Cómo configurar el portal ARCO, crear solicitudes de derechos en nombre de un titular y seguir cada caso hasta su cierre dentro del plazo legal."
url: "https://docs.edugoverna.com/guias/flujo-arco"
---
# Derechos ARCO vía API

La Ley 21.719 reconoce a cada titular los derechos de acceso, rectificación, supresión y oposición — y suma portabilidad y bloqueo — ejercibles ante cada responsable del tratamiento. En esta guía configurarás el portal de recepción, crearás solicitudes en nombre de un titular, las seguirás por API y webhooks, y las cerrarás dentro del plazo. {{ className: 'lead' }}

El ciclo de un caso:

1. Configuras (una vez) tu portal ARCO → `PUT /arco/portal`. Los titulares pueden ingresar solicitudes ahí, o tu plataforma las crea por API.
2. Creas la solicitud → `POST /arco/requests`, respuesta `201` con folio y fecha límite; evento `rights_request.created`.
3. El caso avanza — documentos, prórrogas, exports — → eventos `rights_request.updated`, `rights_request.document.added`, `rights_request.export_ready`.
4. El plazo se acerca o se vence → Edugoverna recuerda por correo al equipo responsable; tu integración lo vigila con `dueAt`.
5. Respondes al titular y cierras → `POST /arco/requests/:id/close`; correo de cierre al solicitante (si el caso tiene email de contacto) y evento `rights_request.closed`.

## El plazo legal

Cada solicitud nace con una fecha límite (`dueAt`) calculada en **días hábiles** — la Ley 21.719 fija el máximo en 20 días hábiles — según la configuración de tu portal ARCO: el valor por tipo de derecho si lo definiste, si no `defaultSlaDays`, y en ausencia de configuración, 15 días hábiles. El vencimiento cae al final del día en horario de Chile continental, y una prórroga fundada puede extenderlo. Cuando el plazo se acerca o se vence, Edugoverna recuerda por correo al equipo responsable dentro de la consola; para tu integración, la fuente de verdad es el `dueAt` de cada caso — vigílalo por polling y no dejes que llegue al límite.

## 1. Configura el portal ARCO

El portal es la puerta pública donde los titulares ejercen sus derechos respecto de **tu** tratamiento como responsable. Vive en `https://app.edugoverna.com/arco/portal/{slug}` y cada credencial de socio ve y administra únicamente el suyo. Requiere `partner.arco_portals.read` para leer y `partner.arco_portals.write` para escribir.

`GET /arco/portal` devuelve `{ "arcoPortal": null }` si aún no lo creas. El alta y la actualización son el mismo `PUT`:

<CodeGroup tag="PUT" label="/arco/portal">

```bash {{ title: 'cURL' }}
curl -X PUT https://app.edugoverna.com/api/partner/v1/organizations/{organizationId}/arco/portal \
  -H "Authorization: Bearer {keyId}.{secret}" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "plataforma-ejemplo",
    "enabled": true,
    "ownerDisplayName": "Plataforma Ejemplo SpA",
    "dpoName": "María Delgado",
    "dpoEmail": "privacidad@ejemplo.cl",
    "privacyContactEmail": "privacidad@ejemplo.cl",
    "policyUrl": "https://ejemplo.cl/politica-privacidad",
    "policyVersion": "2026-1",
    "supportedExportFormats": ["json", "csv", "pdf"],
    "defaultSlaDays": 15
  }'
```

```js
const response = await fetch(
  `https://app.edugoverna.com/api/partner/v1/organizations/${organizationId}/arco/portal`,
  {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${keyId}.${secret}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      slug: "plataforma-ejemplo",
      enabled: true,
      ownerDisplayName: "Plataforma Ejemplo SpA",
      dpoName: "María Delgado",
      dpoEmail: "privacidad@ejemplo.cl",
      privacyContactEmail: "privacidad@ejemplo.cl",
      policyUrl: "https://ejemplo.cl/politica-privacidad",
      policyVersion: "2026-1",
      supportedExportFormats: ["json", "csv", "pdf"],
      defaultSlaDays: 15,
    }),
  }
)

const { arcoPortal } = await response.json()
```

</CodeGroup>

Responde `201` al crear y `200` al actualizar. Los campos principales:

- `slug` — obligatorio, 3–80 caracteres en minúsculas, dígitos y guiones. Es la URL pública y es único en toda la plataforma: si otro portal ya lo usa, la respuesta es `409 ARCO_PORTAL_SLUG_CONFLICT`.
- `enabled` — `true` por defecto; en `false` el portal deja de recibir solicitudes sin perder su configuración.
- `dpoName`, `dpoEmail`, `privacyContactEmail`, `sostenedor`, `ownerDisplayName` — la identificación del responsable que exige la ley en la primera plana del portal.
- `policyUrl`, `policyVersion`, `policyDate` — la política de privacidad publicada; `policyUrl: null` la retira.
- `supportedExportFormats` — formatos ofrecidos para acceso y portabilidad: `json`, `csv`, `pdf`, `xml`.
- `defaultSlaDays` — 1 a 20 días hábiles.
- `primaryColor`, `heroVariant`, `portalIntroText` — apariencia y texto de bienvenida.

## 2. Crea una solicitud en nombre del titular

Cuando el titular ejerce su derecho a través de tu plataforma — un formulario propio, un correo a tu soporte — regístralo por API para que el plazo legal empiece a correr con evidencia. Requiere `partner.rights_requests.write`.

<CodeGroup tag="POST" label="/arco/requests">

```bash {{ title: 'cURL' }}
curl https://app.edugoverna.com/api/partner/v1/organizations/{organizationId}/arco/requests \
  -H "Authorization: Bearer {keyId}.{secret}" \
  -H "Content-Type: application/json" \
  -d '{
    "requestType": "access",
    "requestChannel": "partner_api",
    "requesterSubjectId": "c2a4e8d1-13b7-4f6e-9a20-4e8b7c1d5f30",
    "summary": "La apoderada solicita copia de los datos de su hija tratados por la plataforma.",
    "subjectIds": ["8f3b7f0a-2f9d-4d4e-a1c3-77b2a0f1d942"]
  }'
```

```js
const response = await fetch(
  `https://app.edugoverna.com/api/partner/v1/organizations/${organizationId}/arco/requests`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${keyId}.${secret}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      requestType: "access",
      requesterSubjectId: "c2a4e8d1-13b7-4f6e-9a20-4e8b7c1d5f30",
      summary:
        "La apoderada solicita copia de los datos de su hija tratados por la plataforma.",
      subjectIds: ["8f3b7f0a-2f9d-4d4e-a1c3-77b2a0f1d942"],
    }),
  }
)

const rightsRequest = await response.json()
```

</CodeGroup>

- `requestType` — obligatorio: `access`, `rectification`, `suppression`, `opposition`, `portability` o `blocking`.
- `subjectIds` — obligatorio: los titulares afectados, entre 1 y 200 ids.
- `requesterSubjectId` — quién ejerce el derecho (por ejemplo, la apoderada), cuando no coincide con los afectados.
- `requestChannel` — de dónde vino el ejercicio; por defecto `partner_api`.
- `summary` (hasta 2.000 caracteres) y `legalBasis` (hasta 255) — el contexto que leerá quien tramite el caso.

La respuesta `201` es el caso completo. Entre otros campos:

```json {{ title: 'Respuesta (fragmento)' }}
{
  "id": "7e1c4b9a-2d6f-4a83-9c05-b8f3e6a1d270",
  "requestType": "access",
  "requestChannel": "partner_api",
  "status": "submitted",
  "portalTrackingCode": "ARCO-2026-0318-M3QK7D",
  "submittedAt": "2026-08-25T13:40:12.000Z",
  "dueAt": "2026-09-16T02:59:59.999Z",
  "subjects": [{ "subjectId": "8f3b7f0a-2f9d-4d4e-a1c3-77b2a0f1d942" }],
  "documents": [],
  "messages": [],
  "closures": []
}
```

`portalTrackingCode` es el folio legible que puedes entregar al titular para que siga su caso en el portal.

<Note>
  Registrar una `suppression` no borra nada por sí sola: los trabajos de
  anonimización quedan en espera de una aprobación a cuatro ojos en la consola.
  La API abre el caso y corre el plazo; la ejecución irreversible exige esa
  aprobación humana.
</Note>

## 3. Sigue los casos

Con `partner.rights_requests.read`, el listado acepta `status`, `requestType`, `cursor` y `limit` (máximo 200; ver [Paginación](/paginacion)) y responde `{ rightsRequests, totalMatchedCount, nextCursor }`. El detalle vive en `GET /arco/requests/:rightsRequestId` y responde `404 RIGHTS_REQUEST_NOT_FOUND` si el caso no existe en esa organización.

Para no depender del polling, suscribe la familia `rights_request.*` en [Gestión » Webhooks](/gestion/webhooks):

<Row>
  <Col>

    <Properties>
      <Property name="rights_request.created">
        Se abrió un caso — por API o desde el portal público.
      </Property>
      <Property name="rights_request.updated">
        El caso cambió: una prórroga del plazo, un mensaje agregado al
        expediente.
      </Property>
      <Property name="rights_request.document.added">
        Se agregó un documento al expediente (por ejemplo, el titular subió un
        antecedente desde el portal).
      </Property>
      <Property name="rights_request.export_ready">
        Un export de acceso o portabilidad terminó de construirse.
      </Property>
      <Property name="rights_request.sla_due_soon">
        El plazo legal está por vencer. Está en el catálogo suscribible, pero
        la plataforma aún no lo emite: hoy el aviso llega por correo al equipo
        responsable.
      </Property>
      <Property name="rights_request.sla_overdue">
        El plazo legal venció con el caso aún abierto. Mismo estado que el
        anterior: suscribible, aún sin emisión.
      </Property>
      <Property name="rights_request.closed">
        El caso se cerró con su respuesta final.
      </Property>
    </Properties>

  </Col>
  <Col sticky>

    ```json {{ title: 'Ejemplo de payload (fragmento)' }}
    {
      "event": "rights_request.closed",
      "sourceType": "rights_request",
      "sourceId": "7e1c4b9a-2d6f-4a83-9c05-b8f3e6a1d270",
      "occurredAt": "2026-09-11T14:22:05.000Z",
      "data": {
        "id": "7e1c4b9a-2d6f-4a83-9c05-b8f3e6a1d270",
        "requestType": "access",
        "status": "completed",
        "portalTrackingCode": "ARCO-2026-0318-M3QK7D",
        "dueAt": "2026-09-16T02:59:59.999Z",
        "closures": [
          {
            "outcome": "completed",
            "createdAt": "2026-09-11T14:22:05.000Z"
          }
        ]
      }
    }
    ```

  </Col>
</Row>

El sobre y la verificación de firma son los mismos de toda la plataforma — cabeceras `x-edugoverna-signature` y `x-edugoverna-timestamp` — descritos en [Webhooks](/webhooks).

## 4. Cierra el caso

El cierre registra la respuesta final, notifica por correo al solicitante si el caso tiene un email de contacto (los casos originados en el portal lo traen; los creados por API no llevan email, así que ahí la notificación corre por tu cuenta), y emite `rights_request.closed`:

<CodeGroup tag="POST" label="/arco/requests/:rightsRequestId/close">

```bash {{ title: 'cURL' }}
curl https://app.edugoverna.com/api/partner/v1/organizations/{organizationId}/arco/requests/{rightsRequestId}/close \
  -H "Authorization: Bearer {keyId}.{secret}" \
  -H "Content-Type: application/json" \
  -d '{
    "outcome": "completed",
    "responseSummary": "Se entregó al solicitante el archivo con la totalidad de los datos personales tratados, en formato JSON, junto con el detalle de finalidades y destinatarios."
  }'
```

```js
const response = await fetch(
  `https://app.edugoverna.com/api/partner/v1/organizations/${organizationId}/arco/requests/${rightsRequestId}/close`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${keyId}.${secret}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      outcome: "completed",
      responseSummary:
        "Se entregó al solicitante el archivo con la totalidad de los datos personales tratados, en formato JSON, junto con el detalle de finalidades y destinatarios.",
    }),
  }
)

const closedRequest = await response.json()
```

</CodeGroup>

- `outcome` — `completed` (por defecto), `partially_completed` o `denied`. Una denegación debe fundarse en una causal legal; el fundamento va en el resumen.
- `responseSummary` — obligatorio, 2 a 5.000 caracteres: la respuesta que queda en el expediente y viaja en el correo de cierre al titular.

La respuesta es el caso ya cerrado, con su constancia de cierre en `closures`.

## 5. Qué queda fuera de la API

Dos operaciones son deliberadamente exclusivas de la consola, con una sesión de usuario de por medio:

- **La descarga de exports.** `rights_request.export_ready` te avisa que el archivo de acceso o portabilidad está construido, pero su contenido — datos personales en bruto — solo se descarga desde la consola por quien tiene la sesión y el permiso. La API nunca sirve el archivo.
- **Las decisiones sensibles.** Aprobar una supresión o anonimización (la revisión a cuatro ojos), conceder prórrogas y las demás resoluciones que alteran el expediente de forma irreversible se toman en la consola, donde quedan atribuidas a una persona concreta.

Tu integración abre casos, los observa y los cierra; los momentos irreversibles siguen siendo humanos.

## ¿Qué sigue?

- [Derechos ARCO: conceptos, estados y expediente](/derechos-arco)
- [Referencia del recurso de derechos](/api-organizacion/derechos)
- [Webhooks](/webhooks) y su [gestión](/gestion/webhooks)
- [Errores](/errores) y [límites de tasa](/limites)
