SaaS APIAgency API
POST /admin/agency/{id}/domain/provision
에이전시 커스텀 도메인 연결 비동기 job
도메인 연결 Job
관리자가 수동으로 Cloud DNS managed zone을 만들고 고객에게 NS 값을 안내한 뒤, 버튼 클릭으로 DNS 레코드, Certificate Manager DNS authorization, 인증서, Certificate Map Entry 생성을 비동기 job으로 진행합니다.
서버가 중간에 종료되어도 TB_AGENCY_DOMAIN_JOB의 step, status, locked_until 기준으로 재개됩니다. 실패한 job은 retry API로 다시 QUEUED 상태로 돌릴 수 있습니다.
시작
| 항목 | 값 |
|---|---|
| 메서드 | POST |
| 경로 | /admin/agency/{id}/domain/provision 또는 /ai/admin/agency/{id}/domain/provision |
| 인증 | 필요 |
| 권한 | ROLE_ADMIN |
미할당 DNS Zone 조회
Cloud DNS managed zone에는 있지만 TB_AGENCY.domain에는 아직 연결되지 않은 도메인을 조회합니다.
| 항목 | 값 |
|---|---|
| 메서드 | GET |
| 경로 | /admin/agency/domain/unassigned-zones 또는 /ai/admin/agency/domain/unassigned-zones |
| 인증 | 필요 |
| 권한 | ROLE_ADMIN |
GET /admin/agency/domain/unassigned-zones HTTP/1.1
Host: api.glowb.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...{
"status": "200",
"message": null,
"data": [
{
"zoneName": "brand-zone",
"domain": "brand.com",
"dnsName": "brand.com.",
"visibility": "public",
"description": ""
}
]
}Request Body
Prop
Type
POST /admin/agency/um-portal/domain/provision HTTP/1.1
Host: api.glowb.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"domain": "um-portal.com",
"managedZone": "um-portal",
"includeTestSubdomain": true
}curl -X POST "https://api.glowb.com/admin/agency/um-portal/domain/provision" \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"domain": "um-portal.com",
"managedZone": "um-portal",
"includeTestSubdomain": true
}'const response = await fetch('/admin/agency/um-portal/domain/provision', {
method: 'POST',
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
domain: 'um-portal.com',
managedZone: 'um-portal',
includeTestSubdomain: true,
}),
});
const result = await response.json();상태 조회
| 항목 | 값 |
|---|---|
| 메서드 | GET |
| 경로 | /admin/agency/{id}/domain/status 또는 /ai/admin/agency/{id}/domain/status |
| 인증 | 필요 |
| 권한 | ROLE_ADMIN |
GET /admin/agency/um-portal/domain/status HTTP/1.1
Host: api.glowb.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...실패 재시도
| 항목 | 값 |
|---|---|
| 메서드 | POST |
| 경로 | /admin/agency/{id}/domain/jobs/{jobId}/retry 또는 /ai/admin/agency/{id}/domain/jobs/{jobId}/retry |
| 인증 | 필요 |
| 권한 | ROLE_ADMIN |
FAILED 상태의 job만 retry 대상입니다. retry 후 같은 job이 QUEUED로 돌아가며, 다음 스케줄러 tick에서 마지막 성공 step 이후부터 다시 실행됩니다.
응답
성공 응답 (200 OK)
{
"status": "200",
"message": null,
"data": {
"jobId": 12,
"agencyId": "um-portal",
"domain": "um-portal.com",
"managedZone": "um-portal",
"includeTestSubdomain": true,
"status": "TLS_PENDING",
"step": "TEST_CERT_MAP_ENTRY_READY",
"retryCount": 0,
"errorMessage": null,
"prod": {
"hostname": "um-portal.com",
"address": "8.233.25.196",
"dnsAuthorizationName": "dns-auth-prod-um-portal-com",
"acmeRecordName": "_acme-challenge.um-portal.com.",
"acmeRecordValue": "token.authorize.certificatemanager.goog.",
"certificateName": "cert-um-portal-com-prod",
"certificateMapEntry": "entry-um-portal-com"
},
"test": {
"hostname": "test.um-portal.com",
"address": "8.233.192.191",
"dnsAuthorizationName": "dns-auth-test-test-um-portal-com",
"acmeRecordName": "_acme-challenge.test.um-portal.com.",
"acmeRecordValue": "token.authorize.certificatemanager.goog.",
"certificateName": "cert-test-um-portal-com-test",
"certificateMapEntry": "entry-test-um-portal-com"
},
"createdAt": "2026-07-09T15:00:00",
"updatedAt": "2026-07-09T15:03:00",
"completedAt": null
}
}Response Body
Prop
Type
서버 동작
domain의 A 레코드를 운영 LB IP로 upsert합니다.test.{domain}의 A 레코드를 테스트 LB IP로 upsert합니다.- Certificate Manager DNS authorization을 생성하고 ACME CNAME 값을 Cloud DNS에 upsert합니다.
- Certificate Manager certificate를 생성합니다.
- 기존 Certificate Map에 hostname entry를 생성합니다.
- 인증서가 ACTIVE가 될 때까지
TLS_PENDING상태로 폴링합니다. - 인증서가 ACTIVE가 되면 job 상태를
ACTIVE로 완료합니다.
CORS
에이전시 커스텀 도메인은 코드 allowlist에 직접 추가하지 않습니다. 요청 Origin의 host가 활성 TB_AGENCY.domain과 일치하면 CORS에서 동적으로 허용됩니다.