{
  "components": {
    "schemas": {
      "CredentialLinkRequest": {
        "description": "`POST /v1/credentials/link` 요청 본문 (레거시 register/v1 필드 정합 + v1 확장).\n\nRSA-OAEP 암호문 필드는 라우트가 서버 개인키로 복호화 후\nkind별 credential payload로 변환한다. 평문 credential은\n본 API body 에 직접 전송 금지.\n\nHeaders:\n    Authorization: Bearer console JWT, or Basic client_credential when\n        app_credentials.integration_profile is desktop_agent (ADR-XDATA-XSTAFF-001).\n    standard_external client keys remain 403 on this surface.\n    X-Env-Scope: sandbox/real_test/production (필수).\n    X-Trace-Id / X-Request-Id: 운영 상관관계 (선택).\n    X-Organization-Id: admin_user 위임 hint (선택 — v1 Service 는\n        console_user 만 허용하므로 admin_user 는 403).",
        "properties": {
          "authorization_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "동의 화면에서 돌아온 인가 코드(동의 왕복 provider 전용). RSA 로 감싸지 않는다 - 플랫폼이 고객 브라우저에 URL 로 돌려준 값이고 한 번만 쓸 수 있다.",
            "title": "Authorization Code"
          },
          "biz_number": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "사업자등록번호",
            "title": "Biz Number"
          },
          "business_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "사업자명",
            "title": "Business Name"
          },
          "cert_data": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "인증서 DER (RSA-OAEP base64)",
            "title": "Cert Data"
          },
          "cert_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "인증서 별명",
            "title": "Cert Name"
          },
          "cert_oid": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "인증서 정책 OID",
            "title": "Cert Oid"
          },
          "confirm": {
            "default": false,
            "description": "이미 등록된 같은 아이디의 **비밀번호를 바꾸겠다**는 명시 확인(ID/비밀번호 연동 전용). 값이 같으면 이 칸과 무관하게 아무것도 바꾸지 않는다. 값이 다른데 이 칸이 false 면 거절한다 - 옛 값으로 덮이면 되돌릴 수 없고 기관 세션도 함께 끊어지기 때문이다. 인증서·동의 왕복 연동에는 필요 없다.",
            "title": "Confirm",
            "type": "boolean"
          },
          "display_label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "연결 표시 이름",
            "title": "Display Label"
          },
          "encrypted_pw": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "인증서 비밀번호 (RSA-OAEP base64)",
            "title": "Encrypted Pw"
          },
          "exclude_providers": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "description": "console certificate fan-out 제외 provider 목록. omit/empty = registry certificate_fanout 전체 sibling 연동.",
            "title": "Exclude Providers"
          },
          "is_primary": {
            "default": false,
            "description": "대표 인증서 지정 여부",
            "title": "Is Primary",
            "type": "boolean"
          },
          "key_data": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "개인키 (RSA-OAEP base64)",
            "title": "Key Data"
          },
          "login_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "이용자 ID (RSA-OAEP base64)",
            "title": "Login Id"
          },
          "login_password": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "이용자 비밀번호 (RSA-OAEP base64)",
            "title": "Login Password"
          },
          "provider": {
            "default": "hometax",
            "description": "연동 provider (default hometax — 기존 클라이언트 무중단)",
            "title": "Provider",
            "type": "string"
          },
          "random_enc": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "random_enc (RSA-OAEP base64)",
            "title": "Random Enc"
          },
          "serverTransmissionData": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "레거시 이중 포장 JSON (호환 전용)",
            "title": "Servertransmissiondata"
          },
          "state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "consent-url 이 발급한 state. 우리가 시작한 연결인지 확인한다.",
            "title": "State"
          }
        },
        "title": "CredentialLinkRequest",
        "type": "object"
      },
      "CredentialSelectedAssetsRequest": {
        "description": "`PUT /v1/credentials/{account_link_id}/selected-assets` 요청 본문.\n\n고객이 이 연동에서 조회할 자산을 고른 결과를 **통째로** 보낸다. 키와 값의 모양은\n기관(provider)마다 다르고 상품이 정본을 갖는다 - 그 액션의 `inputs[].key` 를 그대로 쓴다.\n``null`` 을 보내면 선택을 비운다(고르기 전 상태로 되돌린다).",
        "properties": {
          "selected_assets": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "고른 자산 문서. 예) {\"property_id\": [\"properties/123\"], \"site_url\": [\"sc-domain:example.com\"]}. null 이면 선택을 비운다.",
            "title": "Selected Assets"
          }
        },
        "title": "CredentialSelectedAssetsRequest",
        "type": "object"
      },
      "CredentialUnlinkRequest": {
        "description": "`POST /v1/credentials/{account_link_id}/unlink` 요청 본문 (PR-O-5-3).",
        "properties": {
          "unlink_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "폐기 사유 enum: user_request / admin_action / security_incident. None -> user_request (console_user v1 default).",
            "title": "Unlink Reason"
          }
        },
        "title": "CredentialUnlinkRequest",
        "type": "object"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "title": "Detail",
            "type": "array"
          }
        },
        "title": "HTTPValidationError",
        "type": "object"
      },
      "JobSubmitRequest": {
        "description": "`POST /v1/jobs` 요청 본문 (UNIFIED_JOB_INTERFACE §4-1 1:1 정합).\n\nPR-J-3: env_scope 는 본문이 아닌 `X-Env-Scope` 헤더로 이동 (정본 §4-1 line 59).\n`payload` 는 정본 표기 `params` 로 변경, `encrypted_fields` 신규 추가.\n`Idempotency-Key` 는 헤더에서 별도 추출 (정본 §4-1 line 60).",
        "properties": {
          "account_link_id": {
            "anyOf": [
              {
                "minLength": 1,
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "description": "연동 계정 식별자 (선택). 생략 시 API 키 기반 자동 해결. 다중 인증서 환경에서만 명시.",
            "title": "Account Link Id"
          },
          "action": {
            "description": "요청 action — provider 종속 enum",
            "title": "Action",
            "type": "string"
          },
          "encrypted_fields": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "RSA-OAEP base64 암호문 필드 (선택). 평문 dict 저장 금지 — base64 형식 강제.",
            "title": "Encrypted Fields"
          },
          "params": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "description": "액션별 파라미터 (선택). 평문 PII 직접 전송 금지 — encrypted_fields 사용.",
            "title": "Params"
          },
          "provider": {
            "description": "요청 provider (예: hometax) — UNIFIED_JOB_INTERFACE §5 enum",
            "title": "Provider",
            "type": "string"
          }
        },
        "required": [
          "provider",
          "action"
        ],
        "title": "JobSubmitRequest",
        "type": "object"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "title": "Location",
            "type": "array"
          },
          "msg": {
            "title": "Message",
            "type": "string"
          },
          "type": {
            "title": "Error Type",
            "type": "string"
          }
        },
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError",
        "type": "object"
      }
    }
  },
  "info": {
    "description": "통합 REST API 서버 (홈택스 등). Human API guide: https://developer.xdata.kr · OpenAPI Reference: /docs",
    "title": "XBOSS API",
    "version": "2.0.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/v1/credentials/link": {
      "post": {
        "description": "`POST /v1/credentials/link` 단일 진입점 (계획서 §3-2.D 7번째 외부 표면).\n\nPR-O-3: JWT(console_user) or desktop_agent client_credential (ADR-XDATA-XSTAFF-001).\n정책 평가 + user_credentials\nINSERT + `account_link.linked` audit 단일 트랜잭션. 레거시 `register/v1` 도\n동일 `_run_credential_link_pipeline` 경유 (PR-O-4). `register_user_certificate()`\n우회 0건.\n\n응답 분기 (ADR-058 + 결정 큐 D-76):\n    - LINKED                                   -> 201 Created + 2필드 envelope\n    - IDEMPOTENT_MATCH / REACTIVATED / UPDATED -> 200 OK + 2필드 envelope\n    - 정책 거부 (AuthPolicyError)            -> 401/402/403/422/429\n    - Service 거부 (AccountLinkLinkError)    → 5 error_code 정밀 매핑\n    - RSA/필드 검증 ValueError               → 400 VALIDATION_INVALID_FIELD\n    - 그 외 예외                              → 500 INTERNAL_ERROR\n\n같은 신원으로 다시 부를 때 무엇이 되는지는 **자재 값**이 정한다(결정 큐 D-76,\n사용자 결정 2026-09-20 · 선언은\n`identity_credential_link_lifecycle.MATERIAL_REPLACEMENT_BY_CREDENTIAL_KIND`):\n\n    - 값이 같다                 -> ``IDEMPOTENT_MATCH``. 쓰기 0 · 감사 0 · 기관 세션 유지.\n    - 값이 다르다 (인증서)      -> 지문이 자재 자체라 애초에 다른 연동이 된다.\n    - 값이 다르다 (동의 왕복)   -> ``UPDATED``. 동의 화면이 곧 명시 확인이다.\n    - 값이 다르다 (ID/비밀번호) -> ``confirm: true`` 가 없으면 **409 RESOURCE_CONFLICT**\n      (``MATERIAL_REPLACEMENT_NOT_CONFIRMED``). 있으면 ``UPDATED``.\n\n``UPDATED`` 는 전에 이 목록에 없었다 - 덮어쓰기가 문서화되지 않은 조용한 200 이었다.\n\n`Idempotency-Key` 는 선택이다. 헤더가 없으면 위 분기가 그대로다. 헤더를 주면 첫 응답이\n저장되고 같은 키의 재전송은 그 status/body 를 그대로 재생하며 `X-Idempotency-Replay: true`\n를 붙인다(IDEMPOTENCY_STANDARD §4). 만료·본문 불일치는 409 IDEMPOTENCY_KEY_CONFLICT 다.",
        "operationId": "link_credential_v1_v1_credentials_link_post",
        "parameters": [
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "User-Agent",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "User-Agent"
            }
          },
          {
            "description": "선택. 전사 표준 형식(1~128자 ASCII, UUID v4 권장). 주면 같은 키의 재전송이 등록을 두 번 하지 않고 첫 응답을 그대로 돌려준다(X-Idempotency-Replay: true). 결과는 GET /v1/credentials/link-operations 로 같은 키를 주고 조회한다.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "선택. 전사 표준 형식(1~128자 ASCII, UUID v4 권장). 주면 같은 키의 재전송이 등록을 두 번 하지 않고 첫 응답을 그대로 돌려준다(X-Idempotency-Replay: true). 결과는 GET /v1/credentials/link-operations 로 같은 키를 주고 조회한다.",
              "title": "Idempotency-Key"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CredentialLinkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Idempotent match or reactivated credential"
          },
          "201": {
            "description": "New credential linked"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Connected ID (account_link_id) 발급 — 사용자 인증서 연동",
        "tags": [
          "CredentialLink"
        ]
      }
    },
    "/v1/credentials/link-operations": {
      "get": {
        "description": "`GET /v1/credentials/link-operations` — 등록 결과만 읽는다 (U1).\n\n키를 경로 변수가 아니라 헤더로 받는다. 경로에 넣으면 `/` 가 든 키가 라우터에서 404 로\n깨지고, 원문이 URL · 접근 로그에 남는다. 등록 때와 같은 헤더 이름 · 같은 값이다.\n\n상태:\n    - 200 COMPLETED — 등록이 끝났고 그때의 응답 본문을 그대로 돌려준다.\n    - 202 UNKNOWN   — 작업은 있으나 결과가 아직 확정되지 않았다.\n    - 404           — 이 주체에게 보이는 작업이 없다. **실행되지 않았다는 증거가 아니다.**\n    - 409           — 작업 창(24시간)이 지났다 (IDEMPOTENCY_KEY_CONFLICT).\n\n이 경로는 INSERT · lock 재점유 · 등록 dispatcher 를 부르지 않는다.",
        "operationId": "read_credential_operation_v1_v1_credentials_link_operations_get",
        "parameters": [
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "description": "필수. 등록할 때 보낸 것과 같은 키.",
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "필수. 등록할 때 보낸 것과 같은 키.",
              "title": "Idempotency-Key"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Original registration result"
          },
          "202": {
            "description": "Result is not yet known"
          },
          "404": {
            "description": "No visible operation for this key"
          },
          "409": {
            "description": "Operation window expired"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "등록 작업 결과 조회 (Idempotency-Key 헤더)",
        "tags": [
          "CredentialLink"
        ]
      }
    },
    "/v1/credentials/linkable-providers": {
      "get": {
        "operationId": "list_linkable_providers_v1_v1_credentials_linkable_providers_get",
        "parameters": [
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Linkable provider catalog (console credential dialog SSOT)",
        "tags": [
          "CredentialLink"
        ]
      }
    },
    "/v1/credentials/{account_link_id}": {
      "get": {
        "description": "GET /v1/credentials/{account_link_id} — desktop_agent pre-flight probe (E6-c PR3).\n\nRead-only durability helper path (list pattern). Returns 200 when ACTIVE,\n404 when missing/INACTIVE/wrong owner.",
        "operationId": "get_credential_v1_v1_credentials__account_link_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "account_link_id",
            "required": true,
            "schema": {
              "title": "Account Link Id",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Connected ID (account_link_id) ACTIVE probe",
        "tags": [
          "CredentialLink"
        ]
      }
    },
    "/v1/credentials/{account_link_id}/selected-assets": {
      "get": {
        "description": "`GET /v1/credentials/{account_link_id}/selected-assets` - 지금 무엇이 골라져 있나.\n\n화면이 선택 화면을 다시 열 때 이미 고른 것을 표시할 재료다. 값은 저장된 그대로이고,\n아직 고르지 않았으면 ``null`` 이다(빈 선택과 미선택을 엔진이 가르지 않는다).",
        "operationId": "read_credential_selected_assets_v1_v1_credentials__account_link_id__selected_assets_get",
        "parameters": [
          {
            "in": "path",
            "name": "account_link_id",
            "required": true,
            "schema": {
              "title": "Account Link Id",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Stored selection"
          },
          "404": {
            "description": "No such active account link for this user"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "이 연동에 저장된 자산 선택 조회",
        "tags": [
          "CredentialLink"
        ]
      },
      "put": {
        "description": "`PUT /v1/credentials/{account_link_id}/selected-assets` - 고객이 고른 자산을 저장한다.\n\n연동만으로는 조회가 시작되지 않는다. 기관 계정 하나에 GA4 속성 · 사이트가 여러 개 딸려\n올 수 있고 **그중 고객이 고른 것만** 읽어야 하기 때문이다(의뢰서 AT-002). 고를 수 있는\n목록은 그 상품의 상태 조회 액션이 준다 - 화면은 자기가 보여 준 키를 그대로 보낸다.\n\n**통째로 바꾼다.** 부분 수정 경로를 두지 않는 이유는 서비스 docstring 에 적었다.",
        "operationId": "replace_credential_selected_assets_v1_v1_credentials__account_link_id__selected_assets_put",
        "parameters": [
          {
            "in": "path",
            "name": "account_link_id",
            "required": true,
            "schema": {
              "title": "Account Link Id",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CredentialSelectedAssetsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Stored selection"
          },
          "400": {
            "description": "Selected assets document is not storable"
          },
          "404": {
            "description": "No such active account link for this user"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "이 연동에서 조회할 자산 선택 저장",
        "tags": [
          "CredentialLink"
        ]
      }
    },
    "/v1/credentials/{account_link_id}/unlink": {
      "post": {
        "description": "`POST /v1/credentials/{account_link_id}/unlink` 단일 진입점 (PR-O-5-3).\n\nJWT(console_user) or desktop_agent client_credential (ADR-XDATA-XSTAFF-001).\n정책 평가 + user_credentials\nUPDATE (ACTIVE -> INACTIVE) + GCS cert/key 삭제 + `account_link.unlinked`\naudit 단일 트랜잭션.\n\n응답 분기:\n    - 정상 해제                              -> 200 OK + 3필드 envelope\n    - 정책 거부 (AuthPolicyError)            -> 401/402/403/422/429\n    - Service 거부 (AccountLinkUnlinkError)  -> 8 error_code 정밀 매핑\n    - ValueError (account_link_id 형식 등)   -> 400 VALIDATION_INVALID_FIELD\n    - 그 외 예외                              -> 500 INTERNAL_ERROR",
        "operationId": "unlink_credential_v1_v1_credentials__account_link_id__unlink_post",
        "parameters": [
          {
            "in": "path",
            "name": "account_link_id",
            "required": true,
            "schema": {
              "title": "Account Link Id",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "User-Agent",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "User-Agent"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CredentialUnlinkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "Connected ID (account_link_id) 인증서 연동 해제",
        "tags": [
          "CredentialUnlink"
        ]
      }
    },
    "/v1/crypto/public-key": {
      "get": {
        "description": "`GET /v1/crypto/public-key` 단일 진입점 (PR-K-5).\n\nPhase 2 외부 표면 6호 — env_scope 별 ACTIVE + RETIRING JWKS 공개키 회수.\nPR-N-6 list read 패턴 1:1 재사용 (8 원칙 #1 공통모듈화 + #3 일관성).\nSELECT 만이므로 audit 신규 적재 0건 — 정책 평가 자체의\n`auth.policy.evaluation` audit 1건만 §5-11 에서 적재.\n\nenv_scope 전달: ``resolve_env_scope`` dependency — Query ``env_scope`` 또는\n``X-Env-Scope`` 헤더 (AUTH_POLICY_INTERFACE §5-5-i Query 관행 유지, PR-ENV-WIRE).\n\n응답 분기 (CryptoKeyError 2종 + ValueError -> ERROR_CODES.md envelope):\n    - 정상 조회                              -> 200 OK + JWKS envelope\n      ({keys: [{kid, kty, alg, use, n, e}, ...]})\n    - 정책 거부 (AuthPolicyError)            -> 401/402/403/422/429\n      (PR-M 정밀 매핑, 미들웨어 위임)\n    - Service 거부 (CryptoKeyError)          -> 2 error_code 정밀 매핑:\n        * NO_ACTIVE_KEY_FOR_ENV_SCOPE       -> 503 SERVICE_UNAVAILABLE\n        * INVALID_PEM_FORMAT                -> 500 INTERNAL_ERROR\n    - Repository/Service ValueError          -> 400 VALIDATION_INVALID_FIELD\n    - 그 외 예외                              -> 500 INTERNAL_ERROR (미들웨어)\n\n금지 (CRYPTO_KEY_SCHEMA §10): server_public.pem file-based fallback /\ncrypto_keys 직접 SELECT / PEM 분해 — 본 핸들러는 auth_policy_routing\n헬퍼 단일 경로만 사용.",
        "operationId": "get_crypto_public_key_v1_v1_crypto_public_key_get",
        "parameters": [
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "JWKS public key retrieval (CRYPTO_KEY_SCHEMA §6)",
        "tags": [
          "Crypto"
        ]
      }
    },
    "/v1/jobs": {
      "post": {
        "description": "`POST /v1/jobs` 단일 진입점 (UNIFIED_JOB_INTERFACE §4-1 1:1).\n\nPR-J-3: 501 stub 제거. 정책 평가 + jobs INSERT + `job.submitted` audit 적재\n단일 트랜잭션 (`submit_rest_job_with_audit_durability`). 응답은 정본 §4-1 1:1.\n\n응답 분기:\n    - 신규 INSERT (inserted=True)         → 202 Accepted\n    - 멱등 매칭 (inserted=False, no conflict) → 200 OK\n    - 멱등 충돌 (IdempotencyKeyConflict)  → 409 IDEMPOTENCY_KEY_CONFLICT\n    - 정책 거부 (AuthPolicyError)         → 401/402/403/422/429 (PR-M 정밀 매핑)\n    - 입력 검증 실패 (ValueError)         → 400 VALIDATION_INVALID_FIELD\n    - account_link 소유권 실패            → 404 RESOURCE_NOT_FOUND (PR-J-6)\n    - 그 외 예외                          → 500 INTERNAL_ERROR",
        "operationId": "submit_job_v1_v1_jobs_post",
        "parameters": [
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Idempotency-Key"
            }
          },
          {
            "in": "header",
            "name": "User-Agent",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "User-Agent"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JobSubmitRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "작업 제출 (UnifiedJob 단일 진입점)",
        "tags": [
          "UnifiedJob"
        ]
      }
    },
    "/v1/jobs/{job_id}": {
      "get": {
        "description": "`GET /v1/jobs/{job_id}` (UNIFIED_JOB_INTERFACE §4-2 1:1).\n\nPR-J-4: 단일 잡 상태 조회. `JobRepository.get_by_id` SELECT + 정책 평가 +\nKST aware ISO-8601 응답 직렬화 모두 `auth_policy_routing` 분리 모듈의\n`get_job_for_read` + `serialize_job_read_response` 헬퍼 단일 경로 통과\n(8대 원칙 #1 공통모듈화 + #2 구조화 + #4 진입점 일원화).\n\n응답 분기:\n    - 잡 발견 (정책 통과 + 동일 org/env)    → 200 OK + 응답 10필드 (정본 §4-2)\n    - 잡 부재 (또는 다른 org/env)            → 404 JOB_NOT_FOUND (정보 노출 차단)\n    - 정책 거부 (AuthPolicyError)            → 401/402/403/422/429 (PR-M 정밀 매핑)\n    - PrincipalContext.organization_id None → 400 VALIDATION_INVALID_FIELD\n        (데이터 손상 운영 진단 — 외부 silent 500 fallback 차단, PR-J-4 정합)\n    - JobRepository.get_by_id ValueError    → 400 VALIDATION_INVALID_FIELD\n    - 그 외 예외                             → 500 INTERNAL_ERROR",
        "operationId": "get_job_v1_v1_jobs__job_id__get",
        "parameters": [
          {
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "title": "Job Id",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "작업 상태 조회 (UnifiedJob §4-2)",
        "tags": [
          "UnifiedJob"
        ]
      }
    },
    "/v1/jobs/{job_id}/result": {
      "get": {
        "description": "`GET /v1/jobs/{job_id}/result` (UNIFIED_JOB_INTERFACE §4-3 1:1).\n\nPR-J-5: 단일 잡 결과 조회. UnifiedJobApi 외부 표면 3호 (POST/GET/result) 완성.\n`JobRepository.get_result_by_id` SELECT + 정책 평가 + UNIFIED §4-3 응답\n4필드 직렬화 모두 `auth_policy_routing` 분리 모듈의 `get_job_result_for_read`\n+ `serialize_job_result_response` 헬퍼 단일 경로 통과 (8대 원칙 #1 공통모듈화\n+ #2 구조화 + #4 진입점 일원화).\n\n응답 분기 (UNIFIED §4-3 line 149-150):\n    - 잡 부재 (또는 다른 org/env)            → 404 JOB_NOT_FOUND (정보 노출 차단)\n    - status != 'SUCCEEDED'                  → 409 JOB_INVALID_TRANSITION\n    - status == 'SUCCEEDED' + inline 정상     → 200 OK + result.data\n    - status == 'SUCCEEDED' + storage_uri    → 200 OK + result.download_url\n      (ADR-069 · sign_job_result_download_url). allowlist/sign 실패 → 500\n    - 정책 거부 (AuthPolicyError)            → 401/402/403/422/429 (PR-M)\n    - PrincipalContext.organization_id None → 400 (운영 진단)\n    - JobRepository.get_result_by_id ValueError → 400 VALIDATION_INVALID_FIELD\n    - 그 외 예외                             → 500 (미들웨어 fallback)",
        "operationId": "get_job_result_v1_v1_jobs__job_id__result_get",
        "parameters": [
          {
            "in": "path",
            "name": "job_id",
            "required": true,
            "schema": {
              "title": "Job Id",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "env_scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Env Scope"
            }
          },
          {
            "in": "header",
            "name": "Authorization",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Authorization"
            }
          },
          {
            "in": "header",
            "name": "X-Env-Scope",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "X-Env-Scope"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": "Successful Response"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            },
            "description": "Validation Error"
          }
        },
        "summary": "작업 결과 조회 (UnifiedJob §4-3)",
        "tags": [
          "UnifiedJob"
        ]
      }
    }
  },
  "x-xdata-provider-input-contracts": [
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": true,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "random_enc_description": "이 인증서에서 얻은 VID 보조값 원문 문자열입니다. 임의의 난수가 아닙니다. 보조값을 얻는 경로를 먼저 준비하세요.",
        "required": [
          "certificate",
          "private_key",
          "password",
          "random_enc"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data",
          "random_enc": "random_enc"
        }
      },
      "label_ko": "홈택스",
      "link_method": "form",
      "login_contract": {
        "action": "hometax.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "hometax",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": true,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "required": [
          "certificate",
          "private_key",
          "password"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data"
        }
      },
      "label_ko": "국민건강보험공단 EDI",
      "link_method": "form",
      "login_contract": {
        "action": "nhis_edi.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "nhis_edi",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": true,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "random_enc_description": "이 인증서에서 얻은 VID 보조값 원문 문자열입니다. 임의의 난수가 아닙니다. 보조값을 얻는 경로를 먼저 준비하세요.",
        "required": [
          "certificate",
          "private_key",
          "password",
          "random_enc"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data",
          "random_enc": "random_enc"
        }
      },
      "label_ko": "국민연금공단 EDI",
      "link_method": "form",
      "login_contract": {
        "action": "nps_edi.auth.npki_session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {
            "business_management_no": {
              "description": "숫자 11자리입니다. 하이픈을 넣어 보내도 숫자만 남겨 씁니다.",
              "pattern": "^[0-9]{11}$",
              "title": "사업장관리번호",
              "type": "string"
            }
          },
          "required": [
            "business_management_no"
          ],
          "type": "object"
        }
      },
      "provider": "nps_edi",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": true,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "required": [
          "certificate",
          "private_key",
          "password"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data"
        }
      },
      "label_ko": "4대보험",
      "link_method": "form",
      "login_contract": {
        "action": "fourinsure.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "fourinsure",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": true,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "required": [
          "certificate",
          "private_key",
          "password"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data"
        }
      },
      "label_ko": "근로복지공단",
      "link_method": "form",
      "login_contract": {
        "action": "comwel.auth.npki_session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {
            "business_registration_no": {
              "description": "숫자 10자리입니다. 하이픈을 넣어 보내도 숫자만 남겨 씁니다.",
              "pattern": "^[0-9]{10}$",
              "title": "사업자등록번호",
              "type": "string"
            }
          },
          "required": [
            "business_registration_no"
          ],
          "type": "object"
        }
      },
      "provider": "comwel",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": true,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "required": [
          "certificate",
          "private_key",
          "password"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data"
        }
      },
      "label_ko": "고용24",
      "link_method": "form",
      "login_contract": {
        "action": "work24.auth.npki_session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {
            "business_management_no": {
              "description": "사무대행기관 로그인에 함께 넘깁니다.",
              "title": "사업장관리번호",
              "type": "string"
            },
            "business_registration_no": {
              "description": "숫자 10자리입니다. 하이픈을 넣어 보내도 숫자만 남겨 씁니다.",
              "pattern": "^[0-9]{10}$",
              "title": "사업자등록번호",
              "type": "string"
            },
            "isoa_no": {
              "description": "회원유형이 사무대행기관일 때 넘깁니다.",
              "title": "사무대행기관번호",
              "type": "string"
            },
            "member_type_code": {
              "default": "BE904",
              "description": "일반사업자 또는 사무대행기관. 로그인 화면이 유형마다 다릅니다.",
              "enum": [
                "BE904",
                "BE902"
              ],
              "title": "회원유형",
              "type": "string"
            }
          },
          "required": [
            "business_registration_no"
          ],
          "type": "object"
        }
      },
      "provider": "work24",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": true,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "required": [
          "certificate",
          "private_key",
          "password"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data"
        }
      },
      "label_ko": "KB국민카드 기업카드",
      "link_method": "form",
      "login_contract": {
        "action": "kb_biz_card.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "kb_biz_card",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": false,
      "bank_account_credential_mode": "parent_login_child_business",
      "certificate_fanout": false,
      "credential_kind": "id_password",
      "has_sub_credential": true,
      "input_contract": {
        "format": "password-text-v1",
        "identity": "login_id",
        "identity_schema": {
          "minLength": 1,
          "title": "기관 로그인 ID",
          "type": "string"
        },
        "secret": "login_password",
        "secret_schema": {
          "minLength": 1,
          "title": "기관 로그인 비밀번호",
          "type": "string",
          "writeOnly": true
        }
      },
      "label_ko": "신한은행 간편조회",
      "link_method": "form",
      "login_contract": {
        "action": "shinhan_easy.auth.id_password_session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "shinhan_easy",
      "requires_identity_fields": true
    },
    {
      "account_link_auto_resolve": false,
      "bank_account_credential_mode": "parent_login_child_business",
      "certificate_fanout": false,
      "credential_kind": "id_password",
      "has_sub_credential": true,
      "input_contract": {
        "format": "canonical-json-v1",
        "identity": "login_id",
        "identity_normalization": "remove-hyphens-and-whitespace",
        "identity_schema": {
          "pattern": "^[0-9]{14}$",
          "title": "계좌번호",
          "type": "string"
        },
        "secret": "login_password",
        "secret_schema": {
          "additionalProperties": false,
          "properties": {
            "account_password": {
              "pattern": "^[0-9]{4}$",
              "title": "계좌 비밀번호",
              "type": "string",
              "writeOnly": true
            },
            "identity_verification_value": {
              "pattern": "^(?:[0-9]{6}|[0-9]{7})$",
              "title": "본인확인 번호",
              "type": "string",
              "writeOnly": true
            },
            "version": {
              "const": 1,
              "type": "integer"
            }
          },
          "required": [
            "account_password",
            "identity_verification_value",
            "version"
          ],
          "type": "object"
        }
      },
      "label_ko": "IBK기업은행 빠른조회",
      "link_method": "form",
      "login_contract": {
        "action": "ibk_fast_account.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "ibk_fast_account",
      "requires_identity_fields": true
    },
    {
      "account_link_auto_resolve": false,
      "bank_account_credential_mode": "parent_login_child_business",
      "certificate_fanout": false,
      "credential_kind": "id_password",
      "has_sub_credential": true,
      "input_contract": {
        "format": "canonical-json-v1",
        "identity": "login_id",
        "identity_normalization": "remove-hyphens-and-whitespace",
        "identity_schema": {
          "pattern": "^[0-9]{10,16}$",
          "title": "계좌번호",
          "type": "string"
        },
        "secret": "login_password",
        "secret_schema": {
          "additionalProperties": false,
          "properties": {
            "account_password": {
              "pattern": "^[0-9]{4}$",
              "title": "계좌 비밀번호",
              "type": "string",
              "writeOnly": true
            },
            "identity_verification_value": {
              "pattern": "^(?:[0-9]{6}|[0-9]{10})$",
              "title": "본인확인 번호",
              "type": "string",
              "writeOnly": true
            },
            "version": {
              "const": 1,
              "type": "integer"
            }
          },
          "required": [
            "account_password",
            "identity_verification_value",
            "version"
          ],
          "type": "object"
        }
      },
      "label_ko": "KB국민은행 빠른조회",
      "link_method": "form",
      "login_contract": {
        "action": "kb_fast_account.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "kb_fast_account",
      "requires_identity_fields": true
    },
    {
      "account_link_auto_resolve": false,
      "bank_account_credential_mode": "parent_login_child_business",
      "certificate_fanout": false,
      "credential_kind": "id_password",
      "has_sub_credential": true,
      "input_contract": {
        "format": "canonical-json-v1",
        "identity": "login_id",
        "identity_normalization": "remove-hyphens-and-whitespace",
        "identity_schema": {
          "pattern": "^[0-9]{1,20}$",
          "title": "계좌번호",
          "type": "string"
        },
        "secret": "login_password",
        "secret_schema": {
          "additionalProperties": false,
          "properties": {
            "account_password": {
              "pattern": "^[0-9]{4}$",
              "title": "계좌 비밀번호",
              "type": "string",
              "writeOnly": true
            },
            "identity_suffix": {
              "pattern": "^[0-9]{5}$",
              "title": "본인확인 번호",
              "type": "string",
              "writeOnly": true
            },
            "version": {
              "const": 1,
              "type": "integer"
            }
          },
          "required": [
            "account_password",
            "identity_suffix",
            "version"
          ],
          "type": "object"
        }
      },
      "label_ko": "우리은행 빠른조회",
      "link_method": "form",
      "login_contract": {
        "action": "woori_bank.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "woori_bank",
      "requires_identity_fields": true
    },
    {
      "account_link_auto_resolve": false,
      "bank_account_credential_mode": "parent_login_child_business",
      "certificate_fanout": false,
      "credential_kind": "id_password",
      "has_sub_credential": true,
      "input_contract": {
        "format": "canonical-json-v1",
        "identity": "login_id",
        "identity_normalization": "remove-hyphens-and-whitespace",
        "identity_schema": {
          "pattern": "^[0-9]{11,14}$",
          "title": "계좌번호",
          "type": "string"
        },
        "secret": "login_password",
        "secret_schema": {
          "additionalProperties": false,
          "properties": {
            "account_password": {
              "pattern": "^[0-9]{4}$",
              "title": "계좌 비밀번호",
              "type": "string",
              "writeOnly": true
            },
            "identity_verification_value": {
              "pattern": "^(?:[0-9]{5}|[0-9]{6})$",
              "title": "본인확인 번호",
              "type": "string",
              "writeOnly": true
            },
            "version": {
              "const": 1,
              "type": "integer"
            }
          },
          "required": [
            "account_password",
            "identity_verification_value",
            "version"
          ],
          "type": "object"
        }
      },
      "label_ko": "하나은행 빠른조회",
      "link_method": "form",
      "login_contract": {
        "action": "hana_fast_account.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "hana_fast_account",
      "requires_identity_fields": true
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": false,
      "credential_kind": "oauth_token",
      "has_sub_credential": false,
      "input_contract": {
        "format": "oauth-token-v1",
        "preparation_note": "콘솔에서 동의 화면을 왕복해 발급합니다. 인증서 파일이나 아이디·비밀번호 연결 API 로는 등록하지 않습니다.",
        "required": []
      },
      "label_ko": "Google 마케팅",
      "link_method": "consent_redirect",
      "login_contract": {
        "action": null,
        "note": "이 연동에는 로그인 Job 이 없습니다. 연결만으로 자료 조회를 시작합니다.",
        "params_schema": null
      },
      "provider": "google",
      "requires_identity_fields": false
    },
    {
      "account_link_auto_resolve": true,
      "bank_account_credential_mode": "none",
      "certificate_fanout": false,
      "credential_kind": "certificate",
      "has_sub_credential": false,
      "input_contract": {
        "file_encoding": "base64-before-rsa-oaep-sha256",
        "format": "certificate-files-v1",
        "preparation_note": "DER 인증서와 개인키 bytes, 그리고 인증서 비밀번호를 준비합니다. 값은 우리 공개키로 RSA-OAEP 암호화해 위 전송 칸에 넣습니다 - 미리 따로 암호화하지 않습니다.",
        "required": [
          "certificate",
          "private_key",
          "password"
        ],
        "wire_fields": {
          "certificate": "cert_data",
          "password": "encrypted_pw",
          "private_key": "key_data"
        }
      },
      "label_ko": "위택스",
      "link_method": "form",
      "login_contract": {
        "action": "wetax.session.login",
        "note": "연결이 ACTIVE 인 것과 기관 로그인이 성공한 것은 다릅니다. 여기 적힌 값은 로그인 Job 에 넘기는 것이고, 자료 조회·신고의 params 는 해당 상품 규격을 따릅니다.",
        "params_schema": {
          "additionalProperties": true,
          "properties": {},
          "required": [],
          "type": "object"
        }
      },
      "provider": "wetax",
      "requires_identity_fields": false
    }
  ],
  "x-xdata-unlink-error-codes": [
    {
      "code": "VALIDATION_INVALID_FIELD",
      "status": 400
    },
    {
      "code": "AUTHZ_FORBIDDEN",
      "status": 403
    },
    {
      "code": "RESOURCE_NOT_FOUND",
      "status": 404
    },
    {
      "code": "RESOURCE_CONFLICT",
      "status": 409
    },
    {
      "code": "INTERNAL_ERROR",
      "status": 500
    }
  ]
}
