{
    "info": {
        "_postman_id": "10f94f16-2a58-4def-beeb-b06a22f5e826",
        "name": "Sistema Facturación Perú · Conectar con SFP (OAuth 2.0)",
        "description": "Servidor OAuth 2.0 con **authorization code + PKCE (S256)**, ambos obligatorios, y `state` obligatorio\n(RFC 6749, RFC 7636, RFC 7009 y RFC 9207 para `iss`). Solo inicia sesión y conecta una cuenta que **ya existe**:\nnunca registra empresas ni usuarios.\n\n1. Registramos tu aplicación (Superadmin › Integraciones › Aplicaciones): `client_id` (`sfp_app_…`),\n   `client_secret` (`sfp_secret_…`, se muestra una vez), direcciones de retorno exactas y permisos que puede pedir.\n2. Tu botón abre una ventana emergente en `GET /conectar`. El usuario escribe su RUC, entra con su usuario de siempre\n   en el subdominio de su empresa y pulsa «Permitir».\n3. Volvemos a tu `redirect_uri` con `code` (un solo uso, 5 minutos), `state` e `iss`.\n4. Tu servidor canjea el código en `POST /oauth/token` y recibe `access_token` (1 hora), `refresh_token` (cambia en cada\n   uso) y la dirección de la API v1 de esa empresa (`empresa.api_url`).\n5. Llamas a la API v1 (su referencia está en el mismo portal) con `Authorization: Bearer sfp_oat_…`.\n\nErrores del token: `{ \"error\": \"...\", \"error_description\": \"...\" }` (RFC 6749 §5.2). Guía: https://sistemafacturacionperu.com/desarrolladores/conectar/",
        "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
        "version": "1.0.0"
    },
    "auth": {
        "type": "noauth"
    },
    "variable": [
        {
            "key": "base_url",
            "value": "https://api.sistemafacturacionperu.com",
            "type": "string",
            "description": "Servidor de autorización"
        },
        {
            "key": "api_key",
            "value": "",
            "type": "string",
            "description": "No se usa aquí: el token de acceso sfp_oat_ va en la API v1 de la empresa"
        },
        {
            "key": "client_id",
            "value": "sfp_app_TU_CLIENT_ID",
            "type": "string",
            "description": "El client_id de tu aplicación"
        },
        {
            "key": "client_secret",
            "value": "",
            "type": "string",
            "description": "El client_secret de tu aplicación: guárdalo solo en tu servidor"
        }
    ],
    "item": [
        {
            "name": "Autorización",
            "item": [
                {
                    "name": "Abre la ventana «Conectar con Sistema Facturación Perú»",
                    "request": {
                        "method": "GET",
                        "header": [],
                        "url": {
                            "raw": "{{base_url}}/conectar?response_type=code&client_id=sfp_app_k3j9x0m2q8w1z7c4v6b5n0a1&redirect_uri=&state=&code_challenge=&code_challenge_method=S256",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "conectar"
                            ],
                            "query": [
                                {
                                    "key": "response_type",
                                    "value": "code"
                                },
                                {
                                    "key": "client_id",
                                    "value": "sfp_app_k3j9x0m2q8w1z7c4v6b5n0a1"
                                },
                                {
                                    "key": "redirect_uri",
                                    "description": "Una de las registradas, idéntica."
                                },
                                {
                                    "key": "state",
                                    "description": "Al azar, hasta 500 caracteres. Compruébalo a la vuelta (CSRF)."
                                },
                                {
                                    "key": "code_challenge",
                                    "description": "BASE64URL(SHA256(code_verifier)) sin «=», 43 caracteres."
                                },
                                {
                                    "key": "code_challenge_method",
                                    "value": "S256"
                                },
                                {
                                    "key": "scope",
                                    "value": "comprobantes.emitir comprobantes.leer consultas",
                                    "description": "Permisos separados por espacios (de los que tu aplicación puede pedir). Sin él, todos los registrados.",
                                    "disabled": true
                                }
                            ]
                        },
                        "description": "Se abre en una ventana emergente (o redirección), nunca en un iframe: responde con `X-Frame-Options: DENY`.\nPrimero se validan `client_id` y `redirect_uri` (coincidencia exacta): si fallan, el error se muestra en la\npantalla y **no** se redirige. Con la dirección ya válida, los demás errores vuelven a tu `redirect_uri` como\n`?error=…&error_description=…&state=…&iss=…`."
                    }
                }
            ]
        },
        {
            "name": "Tokens",
            "item": [
                {
                    "name": "Canjea el código o renueva los tokens",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Content-Type",
                                "value": "application/x-www-form-urlencoded"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/oauth/token",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "oauth",
                                "token"
                            ]
                        },
                        "body": {
                            "mode": "urlencoded",
                            "urlencoded": [
                                {
                                    "key": "grant_type",
                                    "value": "authorization_code",
                                    "type": "text"
                                },
                                {
                                    "key": "code",
                                    "value": "sfp_oac_Qm3x…",
                                    "type": "text"
                                },
                                {
                                    "key": "redirect_uri",
                                    "value": "",
                                    "type": "text"
                                },
                                {
                                    "key": "code_verifier",
                                    "value": "",
                                    "type": "text"
                                }
                            ]
                        },
                        "description": "De servidor a servidor. El cliente se autentica con `Authorization: Basic base64(client_id:client_secret)` **o**\ncon `client_id` y `client_secret` en el cuerpo (no las dos). Límite: 30 por minuto por IP y 120 por `client_id`.\n- `authorization_code`: `code`, `redirect_uri` (la misma) y `code_verifier`. Un código canjeado dos veces\n  revoca todo lo que se emitió con él.\n- `refresh_token`: rotatorio. Guarda siempre el nuevo: si reusas uno ya usado, revocamos toda la cadena.",
                        "auth": {
                            "type": "basic",
                            "basic": [
                                {
                                    "key": "username",
                                    "value": "{{client_id}}",
                                    "type": "string"
                                },
                                {
                                    "key": "password",
                                    "value": "{{client_secret}}",
                                    "type": "string"
                                }
                            ]
                        }
                    }
                },
                {
                    "name": "Revoca un token (RFC 7009)",
                    "request": {
                        "method": "POST",
                        "header": [
                            {
                                "key": "Content-Type",
                                "value": "application/x-www-form-urlencoded"
                            }
                        ],
                        "url": {
                            "raw": "{{base_url}}/oauth/revoke",
                            "host": [
                                "{{base_url}}"
                            ],
                            "path": [
                                "oauth",
                                "revoke"
                            ]
                        },
                        "body": {
                            "mode": "urlencoded",
                            "urlencoded": [
                                {
                                    "key": "token",
                                    "value": "",
                                    "type": "text"
                                },
                                {
                                    "key": "token_type_hint",
                                    "value": "access_token",
                                    "type": "text"
                                }
                            ]
                        },
                        "description": "Un `access_token` deja de servir; un `refresh_token` **desconecta la empresa** (como si pulsara «Desconectar»,\nsin aviso: lo pediste tú). Un token desconocido o de otra aplicación responde 200 igual.",
                        "auth": {
                            "type": "basic",
                            "basic": [
                                {
                                    "key": "username",
                                    "value": "{{client_id}}",
                                    "type": "string"
                                },
                                {
                                    "key": "password",
                                    "value": "{{client_secret}}",
                                    "type": "string"
                                }
                            ]
                        }
                    }
                }
            ]
        }
    ]
}
