# Ecobaterías auth.md

Eres un agente. Ecobaterías (https://ecobaterias.org) admite **registro agéntico**: descubrir → registrarse → (reclamo por una persona) → usar la API → revocación. Sigue los pasos en orden.

- Servidor de recursos (API): `https://ecobaterias.org`
- Servidor de autorización: `https://ecobaterias.org`
- Qué protege: cotizaciones numeradas y pedidos de recepción o retiro de baterías de litio. La tarifa es **22 UF por tonelada + IVA**.

Todo lo público sigue abierto y sin credenciales: páginas HTML y Markdown (`Accept: text/markdown`), `/datos/*.json`, `GET https://ecobaterias.org/api/precio`, el servidor MCP `https://ecobaterias.org/api/mcp` y el agente A2A `https://ecobaterias.org/api/a2a`.

## Audiencia

- Agentes de IA que cotizan o solicitan la recepción de baterías de ion litio en nombre de una empresa o persona en Chile.
- Asistentes que solo consultan información: no necesitan registrarse.

## Paso 1 — Descubrir

Una llamada sin credencial a un recurso protegido responde 401 con la ubicación de los metadatos:

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://ecobaterias.org/.well-known/oauth-protected-resource"
```

### 1a. Protected Resource Metadata

```http
GET https://ecobaterias.org/.well-known/oauth-protected-resource
```

```json
{
  "resource": "https://ecobaterias.org",
  "authorization_servers": ["https://ecobaterias.org"],
  "scopes_supported": ["cotizaciones:write", "pedidos:write"],
  "bearer_methods_supported": ["header"]
}
```

### 1b. Authorization Server Metadata

```http
GET https://ecobaterias.org/.well-known/oauth-authorization-server
```

```json
{
  "issuer": "https://ecobaterias.org",
  "token_endpoint": "https://ecobaterias.org/oauth/token",
  "revocation_endpoint": "https://ecobaterias.org/oauth/revoke",
  "jwks_uri": "https://ecobaterias.org/.well-known/jwks.json",
  "grant_types_supported": ["client_credentials"],
  "agent_auth": {
    "skill": "https://ecobaterias.org/auth.md",
    "register_uri": "https://ecobaterias.org/agent/auth",
    "claim_uri": "https://ecobaterias.org/agent/auth/claim",
    "identity_types_supported": ["anonymous"],
    "anonymous": { "credential_types_supported": ["api_key"] }
  }
}
```

- `register_uri`: dónde te registras (paso 3).
- `claim_uri`: dónde una persona inicia el reclamo del registro (paso 4).
- `identity_types_supported`: este servicio solo acepta `anonymous`.
- `anonymous.credential_types_supported`: recibes una `api_key`.

## Paso 2 — Elegir método

Ecobaterías solo admite **anonymous**. No envíes aserciones de identidad (ID-JAG ni correo verificado): responden `issuer_not_enabled`.

## Paso 3 — Registrarse (anonymous)

```http
POST https://ecobaterias.org/agent/auth
Content-Type: application/json

{
  "type": "anonymous",
  "requested_credential_type": "api_key"
}
```

Respuesta 200:

```json
{
  "registration_id": "reg_...",
  "registration_type": "anonymous",
  "credential_type": "api_key",
  "credential": "eba_sk_...",
  "credential_expires": null,
  "scopes": ["cotizaciones:write"],
  "claim_url": "https://ecobaterias.org/agent/auth/claim",
  "claim_token": "clm_...",
  "claim_token_expires": "2026-09-24T12:00:00.000Z",
  "post_claim_scopes": ["cotizaciones:write", "pedidos:write"]
}
```

La `api_key` sirve de inmediato con el scope `cotizaciones:write`. Guarda `credential` como secreto. El `claim_token` se entrega una sola vez: consérvalo solo mientras dure el paso 4. Límite: 10 registros por hora por IP.

## Paso 4 — Reclamo por una persona (necesario para crear pedidos)

Un pedido compromete a una empresa, así que una persona responsable debe reclamar el registro. Al completarlo, la misma `api_key` sube a `pedidos:write`.

### 4a. Iniciar el reclamo

```http
POST https://ecobaterias.org/agent/auth/claim
Content-Type: application/json

{
  "claim_token": "clm_...",
  "email": "persona@empresa.cl"
}
```

Respuesta 200:

```json
{
  "registration_id": "reg_...",
  "claim_attempt_id": "…",
  "status": "initiated",
  "expires_at": "…"
}
```

### 4b. Esperar el código

Ecobaterías envía al instante un código OTP de 6 dígitos a ese correo desde `contacto@ecobaterias.org`; el campo `delivery` de la respuesta anterior confirma si salió. El código dura 48 horas y admite 5 intentos. Si el envío automático falla, el equipo lo manda a mano en horario hábil de Chile (lunes a viernes, 9:00–18:00) y el campo `delivery` lo indica. Dile a tu usuario: "Revisa tu correo de Ecobaterías y léeme el código de 6 dígitos".

### 4c. Enviar el código

```http
POST https://ecobaterias.org/agent/auth/claim/complete
Content-Type: application/json

{
  "claim_token": "clm_...",
  "otp": "123456"
}
```

Respuesta 200:

```json
{ "registration_id": "reg_...", "status": "claimed", "scopes": ["cotizaciones:write", "pedidos:write"] }
```

## Paso 5 — Usar la credencial

Presenta la `api_key` como token Bearer:

```http
POST https://ecobaterias.org/api/cotizaciones
Authorization: Bearer eba_sk_...
Content-Type: application/json

{ "toneladas": 2.5, "tipo_baterias": "vehiculos_electricos" }
```

Si prefieres tokens de corta duración, cambia la `api_key` por un `access_token` JWT (ES256, 15 minutos):

```http
POST https://ecobaterias.org/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=reg_...&client_secret=eba_sk_...
```

```json
{ "access_token": "eyJ...", "token_type": "Bearer", "expires_in": 900, "scope": "cotizaciones:write" }
```

Recursos:

| Método y URL | Scope | Qué hace |
|---|---|---|
| `GET https://ecobaterias.org/api/precio?toneladas=3` | ninguno | Tarifa y cálculo con la UF del día |
| `POST https://ecobaterias.org/api/cotizaciones` | `cotizaciones:write` | Cotización numerada, válida 15 días |
| `GET https://ecobaterias.org/api/cotizaciones?id=COT-...` | cualquiera | Consulta una cotización propia |
| `POST https://ecobaterias.org/api/pedidos` | `pedidos:write` | Solicitud de recepción o retiro (queda `pendiente_confirmacion`) |
| `GET https://ecobaterias.org/api/pedidos?id=PED-...` | cualquiera | Estado de un pedido propio |

Cuerpo de `POST /api/pedidos`:

```json
{
  "toneladas": 2.5,
  "tipo_baterias": "vehiculos_electricos",
  "modalidad": "retiro",
  "direccion_retiro": "Av. Ejemplo 123, Quilicura, Santiago",
  "empresa": { "razon_social": "Empresa SpA", "rut": "76.123.456-7" },
  "contacto": { "nombre": "Nombre Apellido", "email": "persona@empresa.cl", "telefono": "+56 9 1234 5678" },
  "cotizacion_id": "COT-20260917-ABCD1234",
  "notas": "Opcional"
}
```

- `tipo_baterias`: `celulares_notebooks`, `herramientas`, `micromovilidad`, `vehiculos_electricos`, `buses_maquinaria`, `bess` o `mixto`.
- `modalidad`: `entrega_en_planta` o `retiro`.

Ningún pedido se ejecuta solo. Ecobaterías lo confirma con el contacto humano, emite factura con IVA y el pago es por transferencia bancaria. Especificación completa: `https://ecobaterias.org/datos/openapi.json`.

## Errores

| Código | Dónde | Qué hacer |
|---|---|---|
| `invalid_request` (400) | cualquiera | Corrige el cuerpo según el mensaje |
| `issuer_not_enabled` (400) | `/agent/auth` | Usa `"type": "anonymous"` |
| `unsupported_credential_type` (400) | `/agent/auth` | Pide `api_key` |
| `rate_limited` (429) | cualquiera | Espera y reintenta |
| `invalid_claim_token` (400) | `/agent/auth/claim*` | Token incorrecto o ya usado: vuelve al paso 3 |
| `claim_expired` (410) | `/agent/auth/claim*` | Pasaron 7 días: vuelve al paso 3 |
| `previously_claimed` (409) | `/agent/auth/claim*` | Ya fue reclamado: usa tu `api_key` |
| `otp_invalid` (400) | `/agent/auth/claim/complete` | Pide que vuelvan a leer el código |
| `otp_expired` (400) | `/agent/auth/claim/complete` | Código vencido o 5 intentos fallidos: repite el paso 4a |
| `invalid_token` (401) | recursos | Credencial inválida o revocada: vuelve al paso 1 |
| `insufficient_scope` (403) | recursos | Falta `pedidos:write`: completa el paso 4 |
| `invalid_client` (401) | `/oauth/token`, `/oauth/revoke` | `client_id` = `registration_id`, `client_secret` = `api_key` |

Reintentos: 5xx con backoff exponencial; 4xx no repitas el mismo cuerpo.

## Revocación

Revoca un `access_token` o tu propia `api_key` (RFC 7009; responde 200 siempre):

```http
POST https://ecobaterias.org/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=eba_sk_...&client_id=reg_...&client_secret=eba_sk_...
```

Revocar la `api_key` desactiva el registro completo. Ecobaterías también puede revocar un registro por abuso; lo notarás con un 401 `invalid_token`. Reclamos o bajas: contacto@ecobaterias.org con asunto `[agente] revocación`, o WhatsApp +56 9 4011 8111.
