Script 리소스와 엔드포인트
Script는 프런트엔드가 HTTP로 호출하는 선언형 백엔드 엔드포인트입니다(개념과 최상위 구조는 Script 개요에서 다룹니다). 이 페이지는 Script 리소스의 sys 구조와 본문 속성, Script를 저작·실행하는 HTTP 엔드포인트의 명세, 그리고 실행 기록인 ScriptLog를 다룹니다.
Script를 만들고 관리하는 일(목록·조회·생성·수정·삭제)은 CMA(https://cma.weegloo.com/v1)에서 합니다. 실행은 전용 Script 호스트(https://script.weegloo.com/v1)의 실행 경로가 담당하며, 이 실행 경로 하나가 Weegloo User 토큰과 제품에 가입한 회원(ServiceUser) 토큰을 둘 다 받습니다. ACMA에는 Script API가 없고, 읽기 전용 전달 API(CDA, ACDA)에도 없습니다.
Script는 version을 가지는 리소스이며 플랜별 개수 제한을 받는 과금 대상 리소스입니다. 다만 Content나 Media와 달리 발행 상태를 가지지 않습니다. sys에 status나 publish 같은 발행 관련 속성이 없고, 변경할 때마다 version만 올라갑니다. 발행·발행취소 개념이 없으므로 삭제도 발행취소 없이 곧바로 됩니다.
리소스 구조
다음은 Script "t6-http"의 단일 조회 응답입니다. sys(시스템 속성)와 함께 name, definition, 그리고 호출 경로를 여닫는 directCallEnabled·anonymousCallEnabled를 본문 속성으로 가집니다.
{
"sys": {
"id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK",
"type": "Script",
"space": { "sys": { "id": "6jSUUAWT", "type": "Refer", "targetType": "Space" } },
"createdBy": { "sys": { "id": "3p4tcFbQYJNvYTBJf2rYKr42xegQLJ", "type": "Refer", "targetType": "User" } },
"createdAt": "2026-07-15T12:35:47.575Z",
"updatedBy": { "sys": { "id": "3p4tcFbQYJNvYTBJf2rYKr42xegQLJ", "type": "Refer", "targetType": "User" } },
"updatedAt": "2026-07-15T12:35:47.575Z",
"version": 1
},
"name": "t6-http",
"directCallEnabled": true,
"anonymousCallEnabled": false,
"definition": {
"method": "Post",
"statements": [
{
"name": "resp",
"method": "POST",
"url": "https://postman-echo.com/post",
"headers": [ { "key": "Content-Type", "value": "application/json", "secret": false } ],
"body": { "prompt": "{ /payload/prompt }" },
"timeoutMs": 10000,
"retry": 0,
"type": "Http"
},
{
"value": { "status": "{ /resp/status }", "prompt": "{ /resp/body/json/prompt }" },
"isError": false,
"statusCode": 200,
"type": "Return"
}
]
}
}주요 키:
sys.id: Script의 고유 식별자입니다. 단일 조회·수정·삭제·실행 경로의{scriptId}에 들어갑니다.name: Script의 이름입니다(1~64자). 화면 목록과 관리용 식별에 쓰입니다.definition: 이 Script가 무엇을 하는지 선언하는ScriptDefinition입니다. 호출 메서드(method), 문(statements) 배열, 선택적 payload 스키마(payloadSchema)로 이루어집니다. 자세한 구조는 아래 정의와 이름과 Script 개요의 최상위 구조에서 다룹니다.directCallEnabled: 이 Script를/execute로 직접 호출할 수 있는지 여부입니다(불리언, 생략 시true).false면 직접 호출이 거부됩니다. 이 Script를 실행하는 다른 경로는 그대로 남습니다. Webhook의 연결 액션(script)과 Scheduler는 이 엔드포인트를 지나지 않으므로 그대로 실행합니다.anonymousCallEnabled: 이 Script를 인증 없이/execute/anonymous로 호출할 수 있는지 여부입니다(불리언, 생략 시false). 켜면 토큰을 실을 수 없는 제3자도 그 경로로 이 Script를 실행할 수 있고, 실행은 작성자 신원으로 이루어집니다. 조건과 저장 규칙은 아래 익명 호출에서 다룹니다.
sys에 status·publish·archive가 없다는 점에 유의하세요. Script는 전달 경로에 발행되는 리소스가 아니라, 관리 API에서 저작·실행하는 리소스입니다.
시스템 속성 (sys)
모든 Script는 공통 시스템 속성을 sys 객체에 담습니다. space, createdBy, updatedBy는 Refer 모양({ "sys": { "id", "type": "Refer", "targetType" } })으로 들어갑니다.
| 속성 | 타입 | 설명 |
|---|---|---|
id | string | 리소스 고유 식별자. |
type | string | 리소스 종류. Script는 항상 "Script". |
space | Refer<Space> | 이 Script가 속한 Space. |
createdBy | Refer<User> | 생성한 사용자. |
createdAt | string (date-time) | 생성 시각. |
updatedBy | Refer<User> | 마지막으로 수정한 사용자. |
updatedAt | string (date-time) | 마지막 수정 시각. |
version | integer (≥1) | 리소스 버전. 생성·수정마다 1씩 올라갑니다. |
Content·Content Type·Media의 sys에 있는 status(발행 상태)와 publish(발행 이력)가 Script에는 없습니다. Script는 발행되지 않기 때문입니다. archive 속성도 없습니다. 그래서 Script의 version은 발행 없이 순수하게 생성·수정 횟수만큼 증가합니다.
정의와 이름 (name, definition)
Script의 본문 속성은 name, definition, directCallEnabled, anonymousCallEnabled 넷입니다.
| 속성 | 필수 | 설명 |
|---|---|---|
name | 필수 | Script의 이름. 1~64자. |
definition | 필수 | ScriptDefinition. 아래 표의 키로 이루어집니다. |
directCallEnabled | 선택 | 이 Script를 /execute로 직접 호출할 수 있는지 여부. 불리언, 생략 시 true. false면 직접 호출이 거부됩니다. Webhook의 연결 액션(script)과 Scheduler는 이 엔드포인트를 지나지 않으므로 그대로 실행합니다. |
anonymousCallEnabled | 선택 | 이 Script를 인증 없이 /execute/anonymous로 호출할 수 있는지 여부. 불리언, 생략 시 false. 아래 익명 호출 참조. PUT은 전체 교체라 생략하면 false로 돌아갑니다. |
definition(ScriptDefinition)의 키:
| 키 | 필수 | 설명 |
|---|---|---|
method | 필수 | 이 Script를 호출할 HTTP 메서드. Get·Post·Put·Patch·Delete 중 하나. 실행 시 이 값으로 매칭합니다. |
statements | 필수 | 실행할 문(statement)의 순서 있는 배열. 최소 1개. |
payloadSchema | 선택 | JSON Schema. 지정하면 실행 전에 요청 payload를 이 스키마로 검증합니다. |
statements 배열에 넣는 각 문의 종류와 필드는 Statement 카탈로그에서, 값을 흘려보내는 { /pointer } 표현식은 값 표현식에서 다룹니다.
위 예시 "t6-http"의 definition은 method가 Post이고, Http 문으로 외부 API를 호출한 뒤 Return 문으로 그 결과를 돌려줍니다. Http처럼 외부 호출이 있는 문은 자기 몫의 시간을 선언하고, 그만큼이 한 번의 실행에 주어지는 시간에 더해집니다(한 번의 실행에 주어지는 시간 참조).
제약
| 대상 | 제약 |
|---|---|
name | 1~64자, 필수. |
definition.statements | 최소 1개, 필수. |
한 정의당 외부 호출(Http·EmailSend) | 플랜별(요금제 참조). |
| 한 정의당 전체 statement | 플랜별(요금제 참조, 중첩 포함). |
한 정의당 SetVar | 최대 10개(기본값, 중첩 포함). |
Regex.pattern | 최대 128자. |
anonymousCallEnabled가 true인 정의 | where에 createdBy: ":self"를 쓸 수 없음. 아래 익명 호출 참조. |
| 다른 리소스가 참조하는 Script | 삭제할 수 없음. Webhook이 연결 액션으로 참조하거나 Scheduler가 실행 대상으로 참조하면 삭제가 거부되며, 돌아오는 코드는 참조하는 쪽마다 다릅니다(꺼 둔 Scheduler도 마찬가지. 오류 참조). |
위 정적 제약은 Script를 저장(생성·수정)하는 시점에 검사되며, 위반하면 저장이 거부됩니다. 외부 호출 수와 전체 statement 수는 유효성 오류가 아니라 플랜 한도라서, 같은 정의가 상위 플랜에서는 허용됩니다.
저장 시에는 권한과 리소스 종류도 함께 검사합니다.
- 작성자가 그 statement들이 쓰는 리소스·액션 권한을 실제로 갖는지 검사합니다(하나라도 없으면 저장이 거부됩니다. 오류 참조). 회원(ServiceUser)을 읽는 문은 권한 맵이 아니라 SpaceRole
settings의SETTING_SERVICE_LOGIN으로 검사합니다. - 회원(ServiceUser)을 변경하는 문이 들어 있으면 저장을 거부합니다. 이 리소스는 Script에서 읽기만 되므로, 어떤 역할로도 저장할 수 없습니다.
자세한 규칙과 시간 예산, 실행 중 검사되는 값 길이 상한은 실행 시맨틱, 제약, 보안에서 다룹니다.
Script는 과금 대상 리소스로, Organization당 개수가 플랜별로 제한됩니다(Free 10 / Basic 30 / Pro 100 / Enterprise 무제한). 한도에 도달하면 새 Script 생성이 거부됩니다(플랜별 개수 한도 참조).
익명 호출 (anonymousCallEnabled)
anonymousCallEnabled를 true로 두면 그 Script는 인증 없는 전용 경로로도 실행됩니다.
{method} https://script.weegloo.com/v1/spaces/{spaceId}/scripts/{scriptId}/execute/anonymous이것이 필요한 경우는 드뭅니다. 결제 대행사(PG·MoR)처럼 우리에게 콜백을 보내야 하는데 커스텀 헤더를 지원하지 않아 Access Token을 실을 방법이 없는 제3자를 위한 장치입니다. 토큰을 실을 수 있는 호출자는 전부 인증 경로(/execute)를 씁니다.
- 인증 경로는 그대로입니다.
/execute는 여전히 Bearer 토큰과 Script Execute 권한을 요구합니다. 무인증이 되는 것은/execute/anonymous이 경로 하나뿐입니다. - 토큰을 받지 않습니다. 토큰을 실어 보내도 무시되고 실행은 늘 작성자 신원입니다. 호출자 신원으로 실행하려면
/execute를 씁니다. - 게이트 둘을 모두 지나야 합니다.
anonymousCallEnabled가false면 인증되지 않은 접근으로 거부되고,directCallEnabled가false면 직접 호출이 막혀 있어 거부됩니다. 돌아오는 코드는 어느 게이트에 걸렸는지에 따라 다릅니다(오류 참조). 익명 허용 여부를 먼저 보므로, 자격 없는 호출자는 그 Script의 설정 상태를 알아낼 수 없습니다. - 그다음은
/execute와 같습니다. 요청 HTTP 메서드가definition.method와 일치해야 하고, Organization의 Script 실행 쿼터를 소모하며 사용량으로 계량됩니다. - 이 경로는 인증 실행 경로와 같은 Script 호스트(
https://script.weegloo.com/v1)에 있습니다.
작성자 신원으로 실행됩니다
호출자가 없으므로 실행은 그 Script를 만든 사용자(sys.createdBy)의 신원으로 이루어집니다.
- Script 안에서 만들거나 고친 Content·Media의
createdBy·updatedBy가 작성자로 들어갑니다(익명 호출자가 아닙니다. 귀속시킬 다른 신원이 없습니다). where의createdBy: ":self"도 호출자가 아니라 작성자로 풀립니다. 인증 호출자를 전제로 써 둔 소유권 필터를 그대로 두고 익명을 켜면 조용히 작성자의 리소스가 열리므로, 그런 정의는 애초에 저장되지 않습니다(아래).
저장 시 추가 검사
anonymousCallEnabled가 true인 Script에는 규칙이 하나 더 붙습니다.
| 규칙 | 코드 |
|---|---|
ResourceFind·ResourceForEach의 where에 createdBy: ":self"를 쓸 수 없음 | 오류 참조 |
익명 호출에는 호출자 신원이 없어 :self가 작성자로 풀리기 때문입니다. 인증 호출자를 전제로 써 둔 소유권 필터가 조용히 뚫리는 것을 저장 시점에 막습니다.
실질적 인증은 Script가 스스로 합니다
이 경로에는 플랫폼이 걸어 주는 인증이 없습니다. URL을 아는 누구든 호출할 수 있고, 그 호출은 Organization의 Script 실행 쿼터를 소모하며 별도 레이트리밋이 없습니다. 그래서 익명 Script는 자기가 받은 요청을 스스로 검증해야 합니다.
- 맨 앞에
Signature를 두어{ /rawPayload }에 대한 서명을 확인하고, 통과하지 못하면Return으로 그 자리에서 끊습니다. 완결 예시는 쿡북의 웹훅 서명 검증에 있습니다. /now로 replay window까지 검사하면 지난 요청을 다시 보내는 것도 막습니다(/now).- 익명 Script에는 그 콜백이 실제로 해야 하는 일만 담습니다. Script는 작성자의 권한을 위임받아 실행되므로, 담은 만큼이 무인증으로 열립니다(보안 모델).
ScriptLog
Script가 한 번 실행될 때마다 기록이 하나 남습니다. 이 기록이 ScriptLog입니다. 조회 전용이며 생성·수정·삭제 엔드포인트가 없습니다. 경로는 /spaces/{spaceId}/scripts/{scriptId}/logs이고, 기준 URL은 실행 호스트가 아니라 CMA인 https://cma.weegloo.com/v1입니다. 읽으려면 그 Script의 Read 권한이 필요합니다.
{
"sys": {
"id": "3trmXRM7pLdV5Rz8kWq2NcHfJt4bYs",
"type": "ScriptLog",
"space": { "sys": { "id": "6jSUUAWT", "type": "Refer", "targetType": "Space" } },
"script": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } },
"trigger": { "sys": { "id": "3trmXRMZcTAjDnphewjj1AaxYcaxlK", "type": "Refer", "targetType": "Script" } },
"requestId": "3trmXRM9wTbK4Vz7hLp2QsNdRf6cYm",
"returned": true,
"value": { "status": 200, "prompt": "여름 원피스 상품 설명 3줄" },
"success": true,
"statusCode": 200,
"durationMs": 195,
"createdBy": { "sys": { "id": "3p4tcFbQYJNvYTBJf2rYKr42xegQLJ", "type": "Refer", "targetType": "User" } },
"createdAt": "2026-07-15T12:41:03.902Z",
"updatedBy": { "sys": { "id": "3p4tcFbQYJNvYTBJf2rYKr42xegQLJ", "type": "Refer", "targetType": "User" } },
"updatedAt": "2026-07-15T12:41:03.902Z"
}
}모든 값이 sys 안에 있고 본문 속성은 없습니다. 값이 없는 키는 응답에서 빠집니다.
| 속성 | 타입 | 설명 |
|---|---|---|
id | string | 기록의 고유 식별자. |
type | string | 항상 "ScriptLog". |
space | Refer<Space> | 이 기록이 속한 Space. |
script | Refer<Script> | 실행된 Script. |
trigger | Refer | 이 실행을 일으킨 것. 아래 설명 참조. |
requestId | string | 이 실행의 식별자. 실행 응답 봉투의 requestId와 같은 값입니다. |
returned | boolean | Return 문에 도달했는지 여부. |
value | any | 도달한 Return이 돌려준 값입니다. 객체·배열·스칼라 무엇이든 그대로 실립니다. 실패했으면 실패 사유가 여기 담깁니다. |
success | boolean | 성공 여부. |
statusCode | integer | 도달한 Return이 정한 상태 코드. |
durationMs | integer | 실행 소요 시간(밀리초). |
createdBy | Refer<User> 또는 Refer<ServiceUser> | 이 기록이 귀속되는 신원. 아래 설명 참조. |
createdAt | string (date-time) | 기록 생성 시각. |
updatedBy | Refer<User> 또는 Refer<ServiceUser> | createdBy와 같습니다. |
updatedAt | string (date-time) | createdAt과 같습니다. |
trigger는 이 실행을 일으킨 것을 가리킵니다. 직접 호출이면 그 Script 자신, Webhook의 연결 액션으로 실행됐으면 그 Webhook, Scheduler가 돌린 것이면 그 Scheduler입니다.
requestId는 실행 응답 봉투의 requestId와 같은 값입니다. 호출자가 받은 응답에서 그 실행의 기록을 찾을 때 이 값을 기준으로 씁니다.
기록은 실행이 끝난 뒤에 한 번 쓰이고 바뀌지 않습니다. 성공한 실행은 1시간, 실패한 실행은 3일 뒤에 사라집니다. 그보다 오래 남겨야 하는 값은 Script 안에서 Content로 저장하세요.
createdBy는 그 실행이 어느 신원으로 수행됐는지를 가리킵니다. Weegloo User 토큰으로 부른 실행은 그 사용자이고, 회원(ServiceUser) 토큰으로 부른 실행은 그 회원입니다. 호출자가 없는 실행은 신원이 트리거에서 옵니다. 익명 실행은 그 Script의 작성자, Scheduler가 돌린 실행은 그 Scheduler를 만든 사용자(Script 작성자와 다를 수 있습니다), Webhook이 실행한 것은 그 Webhook을 만든 사용자입니다. Webhook의 runAs는 Script 안의 작업이 누구 이름으로 이루어지는지를 정할 뿐이고, 이 로그의 귀속은 바꾸지 않습니다.
오류
Script를 호출하거나 삭제할 때 나오는 코드입니다. 정의를 저장할 때 나오는 코드는 실행 시맨틱, 제약, 보안의 오류에, 값 표현식 규칙을 어긴 코드는 값 표현식의 오류에, 모든 리소스에 공통인 코드는 공통 오류에 있습니다.
| 코드 | 조건 |
|---|---|
WGL422066 | 삭제하려는 Script를 Webhook이 연결 액션으로 참조하고 있습니다(꺼 둔 Webhook도 마찬가지입니다). |
WGL422110 | 삭제하려는 Script를 Scheduler가 실행 대상으로 참조하고 있습니다(꺼 둔 Scheduler도 마찬가지입니다). |
WGL401001 | anonymousCallEnabled가 false인 Script를 익명 실행 경로(/execute/anonymous)로 호출했습니다. |
WGL422062 | directCallEnabled가 false인 Script를 실행 경로(/execute·/execute/anonymous)로 직접 호출했습니다. |
WGL400007 | 실행 요청의 HTTP 메서드가 그 Script의 definition.method와 다릅니다. 요청 본문을 보냈는데 그것이 JSON 객체가 아닐 때, 그리고 definition.payloadSchema를 둔 Script에서 본문이 그 스키마를 만족하지 못할 때도 같은 코드로 거부합니다. |
WGL408002 | 실행이 시간 예산을 넘겨 중단됐습니다. 그 지점까지의 실행 기록은 ScriptLog에 남습니다. |
API
아래 다섯 개(목록·조회·생성·수정·삭제)의 기준 URL은 CMA인 https://cma.weegloo.com/v1이며, Authorization 헤더에 CMA를 인증하는 Bearer 토큰이 필요합니다. 수정은 낙관적 동시성 제어를 위해 X-Weegloo-Version 헤더(현재 리소스의 sys.version)를 함께 보내야 합니다. 맨 아래 ScriptLog 조회 두 개도 같은 CMA 기준 URL을 씁니다.
실행 엔드포인트 두 개의 기준 URL은 전용 Script 호스트인 https://script.weegloo.com/v1입니다. 인증된 실행(/execute)은 Weegloo User 신원의 Bearer 토큰과 회원(ServiceUser) 신원의 Bearer 토큰을 둘 다 받으며, 어느 쪽이든 호출자에게 그 Script의 Execute 권한이 필요합니다.
익명 실행(/execute/anonymous)만 예외로 인증 헤더를 요구하지 않습니다. 같은 Script 호스트에 있고, 그 Script가 anonymousCallEnabled를 켜 두었을 때에만 도달합니다(위 익명 호출 참조).
위 인증 실행 예시의 응답에는 return이 없습니다. 대상 Script가 값을 담은 Return에 도달하지 않고 끝났기 때문입니다(이때 statusCode는 기본값 200). 익명 실행 예시처럼 Return으로 값을 돌려주면 응답에 return(또는 Return.isError가 참이면 error)이 실립니다. 응답의 전체 규칙은 Script 개요의 요청과 응답에서 다룹니다.
관련 문서
- Script 개요: 최상위
ScriptDefinition구조, 요청과 응답, 한 번의 실행에 주어지는 시간을 다룹니다. - Statement 카탈로그:
statements에 넣는 각 문의 필드와 결과를 다룹니다. - 값 표현식:
{ /pointer }참조와 JsonLogic 연산을 다룹니다. - 실행 시맨틱, 제약, 보안: 정적 제약, 플랜별 개수 한도, 권한과 보안 모델을 다룹니다.
- SpaceRole·ServiceUserRole: Script의 액션 권한(
Execute포함)을 역할에 부여하는 방법을 다룹니다.
