{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"2a331c10-7383-48fb-8bbc-c4418095c034","name":"Zipdoc Open API v1.0","description":"# 집닥 서비스 연동\n\n# 집닥 Open API v1.0\n\n협력사 서비스와 집닥 서비스를 연동하기 위한 Open API 가이드입니다.\n\n## 연동 구조\n\n집닥 연동은 성격이 다른 두 개의 레인으로 구성됩니다.\n\n| 레인 | 담당 | 내용 |\n| --- | --- | --- |\n| 웹 서비스 | 프론트엔드 / 앱 | 인앱 웹뷰로 집닥 견적 신청 페이지를 호출합니다. 화면은 집닥이 제공하고, 진입과 회원 식별만 파트너사가 담당합니다 |\n| Open API | 백엔드 서버 | 이 컬렉션이 다루는 영역입니다. 발급받은 자격증명으로 토큰을 얻어 개방 리소스를 조회합니다 |\n\n웹 레인(웹뷰 진입 규약, 랜딩 경로, 진입 파라미터)은 **\\[집닥 서비스 연동 가이드\\]** 문서를 참고하세요.\n\n## 회원 식별자 — `external_token` 과 `vUuid`\n\n두 값은 **동일한 값이며, 레이어별로 이름을 분리**했습니다.\n\n| 레이어 | 파라미터명 | 사용처 |\n| --- | --- | --- |\n| 프론트엔드 (웹뷰 진입) | `external_token` | 웹뷰 진입 URL의 쿼리 파라미터 |\n| 백엔드 (Open API) | `vUuid` | 견적 조회 API의 쿼리 파라미터 |\n\n- 파트너사가 자사 회원 식별자를 해싱·암호화하여 생성한 값입니다. **원본 회원 식별자는 전달하지 않습니다.**\n    \n- 웹뷰 진입 시 `external_token` 으로 전달된 값을 기준으로 견적 신청 건이 해당 회원에게 귀속됩니다.\n    \n- 이후 백엔드에서 그 회원의 견적을 조회할 때 동일한 값을 `vUuid` 로 전달합니다.\n    \n- 따라서 **동일 회원에 대해 항상 같은 값이 생성되어야** 견적 귀속과 조회가 일치합니다.\n    \n\n## 테스트 서버 연동 시작하기\n\n1. 연동/협업/계약 완료 후 집닥 담당자로부터 테스트 계정 생성 및 내부 연동 정보(utm 정보) 발급 받습니다.\n    \n2. 집닥 담당자로부터 `apiKey` / `apiSecret` 을 발급받습니다.\n    \n3. 호출할 서버 및 집닥 서비스(`https://www.zipdocdev.com`)의 공인 IP(CIDR)를 집닥에 등록 신청합니다.\n    \n\n### 프론트엔드 서비스 연동\n\n집닥 연동 페이지 URL:\n\nhttps://{집닥-도메인}/3x8yna?utm_source={utm_source}&utm_campaign={utm_campaign}&utm_medium={utm_medium}&external_token={external_token}\n\n**파라미터**\n\n| 파라미터 | 필수 | 발급 | 설명 |\n| --- | --- | --- | --- |\n| `utm_source` | 필수 | 집닥 | 유입 채널 식별자. 파트너사별로 집닥이 지정합니다 |\n| `utm_campaign` | 필수 | 집닥 | 캠페인 구분. 자사 채널 유입은 `owned` |\n| `utm_medium` | 필수 | 집닥 | 진입 지면 구분 (`banner`, `tile` 등). |\n| `external_token` | 필수 | 파트너사 | 해싱·암호화된 회원 식별자. **견적 신청 건을 파트너사 회원에 귀속하는 기준 키**입니다. 누락 시 회원 귀속이 이루어지지 않아 `/v1/estimates` 계열 API로 조회되지 않습니다 |\n\n## 환경 (웹 서비스)\n\n| 환경 | 집닥 서비스 URL |\n| --- | --- |\n| 개발 | `https://www.zipdocdev.com` |\n| 운영 | 오픈 시 안내 |\n\n### Open API v1.0 연동\n\n| 변수 | 설명 |\n| --- | --- |\n| `baseUrl` | API 도메인 (아래 환경 참고) |\n| `apiKey` | 발급받은 API 키 |\n| `apiSecret` | 발급받은 API 시크릿 |\n| `accessToken` | 스크립트가 자동으로 채웁니다. 직접 입력하지 마세요 |\n| `tokenExpiresAt` | 스크립트가 자동으로 채웁니다 |\n| `vUuid` | 견적 조회 테스트용 회원 식별자 |\n\n`apiKey` / `apiSecret` 은 반드시 **Current value 에만** 입력하세요. Initial value 에 입력하면 컬렉션 공유·Export 시 함께 노출됩니다.\n\n1. 아무 요청이나 실행하면 컬렉션 Pre-request 스크립트가 토큰을 자동 발급·갱신합니다. 토큰 발급을 별도로 먼저 호출할 필요는 없습니다.\n    \n\n## 환경 (Open API)\n\n| 환경 | baseUrl |\n| --- | --- |\n| 개발 | `https://open-apigateway.zipdocdev.com` |\n| 운영 | 오픈 시 안내 |\n\n경로는 `{{baseUrl}}/auth/token`, `{{baseUrl}}/v1/{리소스}` 형태입니다.\n\n## 제공 리소스\n\n| 폴더 | 리소스 | 목록 | 상세 |\n| --- | --- | --- | --- |\n| 1 | 인증 | — | — |\n| 2 | 시공사례 | `GET /v1/interior/cases` | `GET /v1/interior/cases/{id}` |\n| 3 | 사용자 리뷰 | `GET /v1/user/review` | `GET /v1/user/review/{id}` |\n| 4 | 시공사(전문가) | `GET /v1/interior/expert` | `GET /v1/interior/expert/{partnerId}` |\n| 5 | 견적 관리 | `GET /v1/estimates` | `GET /v1/estimates/{id}` |\n| 5 | 견적 관리 (회원별) | `GET /v1/estimates/my` | `GET /v1/estimates/my/{id}` |\n| 5 | 공사 종료 확인 요청/재요청 | `PUT` / `POST /v1/estimates/{id}` | — |\n| 5 | 지역 구분 | `GET /v1/region` | — |\n\n계약 시 등록된 경로만 개방됩니다. 등록되지 않은 경로 호출은 `404` 로 응답합니다.\n\n## 인증\n\n- 모든 요청에 `Authorization: Bearer {accessToken}` 헤더가 필요합니다. 익명 접근은 허용되지 않습니다.\n    \n- 이 컬렉션은 컬렉션 레벨 Bearer 인증을 사용하므로, 하위 요청은 별도 설정 없이 상속받습니다.\n    \n- **Refresh token은 제공하지 않습니다.** 만료 시 `POST /auth/token` 으로 동일하게 재발급하세요.\n    \n- 토큰은 만료 시점까지 재사용하세요. 매 요청마다 발급하면 발급 엔드포인트의 호출 한도에 걸립니다.\n    \n- 토큰 유출이 의심되면 `POST /auth/revoke` 로 즉시 폐기할 수 있습니다.\n    \n\n## 공통 요청 규약\n\n| 항목 | 내용 |\n| --- | --- |\n| `Content-Type` | 본문이 있는 요청은 `application/json` |\n| 페이지 번호 | `page` — 0-base, 기본값 `0` |\n| 페이지 크기 | `size` — 기본값 `20`, 최대 `100` |\n\n목록 응답은 공통 페이징 래퍼입니다.\n\n``` json\n{\n  \"content\": [ ... ],\n  \"page\": 0,\n  \"size\": 20,\n  \"totalElements\": 137,\n  \"totalPages\": 7\n}\n\n ```\n\n## 응답 및 오류 처리\n\n### 상태 코드\n\n| 상태 | 의미 | 대응 |\n| --- | --- | --- |\n| 200 | 성공 | — |\n| 400 | 필수 파라미터 누락 또는 허용 범위 밖의 값 | 요청 파라미터 확인 |\n| 401 | 토큰 없음 / 만료 / 무효 | 토큰 재발급 후 재시도 |\n| 403 | 허용되지 않은 IP, 또는 접근 권한이 없는 리소스 | IP 등록 상태 확인 후 담당자 문의 |\n| 404 | 존재하지 않거나 개방되지 않은 리소스 | 경로 및 식별자 확인 |\n| 429 | 요청 한도 초과 | `X-RateLimit-\\*` 헤더 확인 후 재시도 |\n| 502 / 503 | 일시적 서비스 장애 | 지수 백오프로 재시도 |\n\n### 오류 응답 형식\n\n오류 응답은 다음 형식입니다.\n\n``` json\n{\n  \"error\": \"error.auth.invalid.credentials\",\n  \"traceId\": \"019f491c-1a2b-4c3d-8e9f-0a1b2c3d4e5f\"\n}\n\n ```\n\n| 필드 | 설명 |\n| --- | --- |\n| `error` | 오류 코드 문자열 |\n| `traceId` | 해당 요청의 추적 식별자 |\n\n주요 오류 코드는 다음과 같습니다.\n\n| 코드 | 의미 |\n| --- | --- |\n| `error.required` | 필수 값 누락 |\n| `error.auth.invalid.credentials` | 잘못된 자격증명 또는 정지된 계정 |\n| `error.forbidden` | 접근 권한 없음 |\n| `error.bad.request` | 허용되지 않은 요청 값 |\n| `error.upstream.unavailable` | 상위 서비스 일시 장애 |\n\n**주의할 점**\n\n- `429` 는 **응답 바디가 비어 있습니다.** JSON 파싱을 전제로 한 오류 처리 로직은 이 케이스에서 예외가 발생할 수 있으므로, 상태 코드를 먼저 분기하세요.\n    \n- 상태 변경(`PUT`) 및 재알림(`POST`) 요청은 **성공 시에도 응답 바디가 없습니다.** 성공 판단은 상태 코드 `200` 으로 하세요.\n    \n\n### 추적 헤더\n\n모든 응답에 `ZD-Trace-Id` 헤더가 포함됩니다. 요청 단위 추적 식별자로, 오류 응답 바디의 `traceId` 와 동일한 값입니다.\n\n- 파트너사 로그에 이 값을 함께 기록해 두면 장애 원인 추적이 가능합니다.\n    \n- 문의 시 이 값을 함께 전달해 주시면 확인이 빠릅니다.\n    \n\n## Rate Limit\n\n파트너 단위 토큰 버킷 방식이며, 매 응답에 다음 헤더가 포함됩니다.\n\n| 헤더 | 설명 |\n| --- | --- |\n| `X-RateLimit-Replenish-Rate` | 초당 토큰 보충량 |\n| `X-RateLimit-Burst-Capacity` | 순간 최대 허용량 |\n| `X-RateLimit-Remaining` | 남은 토큰 수 |\n\n`429` 수신 시 최소 1초 대기 후 재시도하고, 연속 실패 시 지수 백오프를 적용하세요.\n\n## 접근 제어\n\n- **IP Allowlist** — 계약 시 등록한 서버 IP(CIDR)에서만 호출할 수 있습니다. 미등록 IP는 유효한 토큰이어도 `403` 입니다.\n    \n- **매체(vendor) 범위 제한** — 견적 관련 API는 액세스 토큰에 연결된 매체 소유 건으로만 접근이 제한됩니다.\n    \n- **리소스 단위 권한** — 추후 도입 예정이며, 도입 시 권한 밖 리소스는 `403` 으로 응답합니다.\n    \n\n## 연동 체크리스트\n\n- `apiKey` / `apiSecret` 안전한 보관 — 코드 저장소 커밋 금지\n    \n- 호출 서버 IP(CIDR) 등록 완료\n    \n- 토큰 캐싱 및 만료 시 자동 재발급 구현 (이 컬렉션의 Pre-request 스크립트 참고)\n    \n- `401` / `429` / `5xx` 재시도 정책 — 지수 백오프 권장\n    \n- `429` 빈 바디 및 성공 시 빈 바디 케이스 처리\n    \n- `ZD-Trace-Id` 로깅\n    \n- `external_token` 생성 규칙이 프론트엔드와 백엔드에서 동일한지 확인\n    \n\n## 버전\n\n`v1.0` — 경로의 `/v1` 이 API 버전입니다. 하위 호환이 깨지는 변경은 새 버전 경로로 제공됩니다.\n\n## 문의\n\nAPI 발급 신청 및 기술 문의: [<b>tech@zipdoc.kr</b>](https://mailto:tech@zipdoc.kr)","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"53091564","team":14171558,"collectionId":"2a331c10-7383-48fb-8bbc-c4418095c034","publishedId":"2sBY4SMJsh","public":true,"publicUrl":"https://docs.zipdoc.co.kr","privateUrl":"https://go.postman.co/documentation/53091564-2a331c10-7383-48fb-8bbc-c4418095c034","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"documentationLayout":"classic-double-column","customisation":{"metaTags":[{"name":"description","value":""},{"name":"title","value":""}],"appearance":{"default":"light","themes":[{"name":"dark","logo":null,"colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"FF6C37"}},{"name":"light","logo":null,"colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"}}]}},"version":"8.12.0","publishDate":"2026-07-29T06:24:48.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"","description":""},"logos":{"logoLight":null,"logoDark":null}},"statusCode":200},"environments":[{"name":"Zipdoc Open API - QA","id":"cf863ab9-bdd1-4bb7-9c9b-afeca0f7c350","owner":"53091564","values":[{"key":"baseUrl","value":"https://open-apigateway.zipdocdev.com","enabled":true,"type":"default"},{"key":"apiKey","value":"","enabled":true,"type":"secret"},{"key":"apiSecret","value":"","enabled":true,"type":"secret"},{"key":"accessToken","value":"","enabled":true,"type":"any"},{"key":"tokenExpiresAt","value":"","enabled":true,"type":"any"},{"key":"vUuid","value":"1acbdb03-8884-4e2a-b04e-a50e875ce861","enabled":true,"type":"default"}],"published":true}],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/327f635dfc480ab3d4c52d36873f24d1e498f68829519f57bfcf7b5a11e831f6","favicon":"https://zipdoc.co.kr/favicon.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"},{"label":"Zipdoc Open API - QA","value":"53091564-cf863ab9-bdd1-4bb7-9c9b-afeca0f7c350"}],"canonicalUrl":"https://docs.zipdoc.co.kr/view/metadata/2sBY4SMJsh"}