apick-api 3.10.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/README.md +468 -466
- package/docs/guide.en.md +363 -359
- package/docs/guide.ko.md +371 -367
- package/docs/tts.md +34 -0
- package/package.json +1 -1
- package/src/index.cjs +33 -13
- package/src/index.d.ts +37 -9
package/docs/guide.ko.md
CHANGED
|
@@ -1,367 +1,371 @@
|
|
|
1
|
-
# apick-api 한국어 가이드
|
|
2
|
-
|
|
3
|
-
## 스킬 성능표
|
|
4
|
-
|
|
5
|
-
`const { data } = await apick.getSkillPerformance()`로 [공개 측정표](https://apick.app/skills/performance)를 조회합니다. 표본 수·시험일·검사 방법·실패 사유를 함께 확인하세요. 모델 점수는 객관적 정확도가 아니며 미검증 값은 `null`입니다. 조회 자체에는 유료 실행이 필요하지 않습니다.
|
|
6
|
-
|
|
7
|
-
## 요청과 응답 형식
|
|
8
|
-
|
|
9
|
-
SDK의 본문 요청은 모두 `multipart/form-data`입니다. `utterance_ids[0]`처럼 배열을 개별 필드로 전송하며 `Content-Type` 헤더를 직접 지정할 필요가 없습니다. GET 조회는 본문을 보내지 않습니다. 기존 JSON 요청도 서버에서 호환용으로 계속 처리합니다.
|
|
10
|
-
|
|
11
|
-
SDK는 줄바꿈 문자열을 `__apick_encoding[필드]=base64-utf8` 메타 항목과 함께 보내 원문의 LF·CR을 보존합니다. Excel 셀은 타입 메타 항목을 함께 사용하며 Date는 ISO 문자열, 배열의 빈 칸은 null로 전달합니다.
|
|
12
|
-
|
|
13
|
-
응답은 서비스별 JSON 또는 파일입니다. 파일 다운로드 실패 시 JSON 오류가 반환될 수 있으며 SDK는 이를 `ApickApiError`로 전달합니다. 직접 REST를 연동할 때는 개발가이드의 OpenAPI 명세와 Postman 컬렉션을 내려받을 수 있습니다. MCP 외부 연결은 기존 JSON-RPC를 사용합니다.
|
|
14
|
-
|
|
15
|
-
`apick-api`는 에이픽의 주요 REST API를 Node.js에서 간단히 호출하기 위한 공식 SDK입니다. 런타임 의존성이 없으며 ESM, CommonJS, TypeScript를 지원합니다.
|
|
16
|
-
|
|
17
|
-
## 설치와 인증
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
npm install apick-api
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
```js
|
|
24
|
-
import { ApickClient } from 'apick-api';
|
|
25
|
-
|
|
26
|
-
const client = new ApickClient({
|
|
27
|
-
apiKey: process.env.APICK_API_KEY,
|
|
28
|
-
timeoutMs: 60_000
|
|
29
|
-
});
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
인증키는 생성자에만 전달하세요. 클라이언트 객체의 열거 가능한 속성에 저장되지 않으며 SDK가 로그로 출력하지 않습니다.
|
|
33
|
-
|
|
34
|
-
마이페이지의 허용 IP가 공란이면 제한 없이 호출할 수 있습니다. 제한하려면 APICK에 도착하는 공인 IPv4를 단일 주소 또는 CIDR(`/32` 등)로 등록하세요. 저장 즉시 반영되며 별도 동기화는 필요하지 않습니다.
|
|
35
|
-
|
|
36
|
-
## 조회와 검증
|
|
37
|
-
|
|
38
|
-
```js
|
|
39
|
-
const business = await client.businessDetails('439-87-00761');
|
|
40
|
-
const venture = await client.ventureBusiness('4398700761');
|
|
41
|
-
const email = await client.validateEmail('sample@example.com');
|
|
42
|
-
const phone = await client.validatePhone('01012341234');
|
|
43
|
-
const holidays = await client.holidays(2026, 10);
|
|
44
|
-
const addresses = await client.searchAddress('가산디지털로', { page: 1 });
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
사업자등록번호의 하이픈은 자동으로 제거합니다. 잘못된 필수값은 네트워크 요청 전에 `TypeError` 또는 `RangeError`로 차단합니다.
|
|
48
|
-
|
|
49
|
-
## 배송조회
|
|
50
|
-
|
|
51
|
-
택배사를 알면 지정조회가 더 정확합니다.
|
|
52
|
-
|
|
53
|
-
```js
|
|
54
|
-
const parcel = await client.trackParcel('cj', '123456789012');
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
택배사를 모르면 자동판별 조회를 사용할 수 있습니다.
|
|
58
|
-
|
|
59
|
-
```js
|
|
60
|
-
const parcel = await client.trackParcelAuto('123456789012');
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## 도메인·검색
|
|
64
|
-
|
|
65
|
-
```js
|
|
66
|
-
const dns = await client.dnsLookup('apick.app');
|
|
67
|
-
const location = await client.geolocate('apick.app');
|
|
68
|
-
const registration = await client.whois('apick.app');
|
|
69
|
-
const web = await client.googleSearch('에이픽 API', { page: 1 });
|
|
70
|
-
const images = await client.googleImageSearch('서울 야경', { page: 1 });
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## OCR
|
|
74
|
-
|
|
75
|
-
PNG와 JPEG를 지원하며 최대 크기는 50MB입니다.
|
|
76
|
-
|
|
77
|
-
```js
|
|
78
|
-
const ocr = await client.ocr('./receipt.jpg');
|
|
79
|
-
console.log(ocr.data.result.full_text);
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
메모리 데이터에는 파일명과 콘텐츠 타입을 지정할 수 있습니다.
|
|
83
|
-
|
|
84
|
-
```js
|
|
85
|
-
await client.ocr(bytes, {
|
|
86
|
-
filename: 'scan.png',
|
|
87
|
-
contentType: 'image/png'
|
|
88
|
-
});
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## 파일 생성
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
await
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
await
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
await
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
let
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
if (
|
|
228
|
-
if (data.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
const
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
console.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
const
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
|
309
|
-
|
|
|
310
|
-
| `
|
|
311
|
-
| `
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
-
|
|
319
|
-
- `
|
|
320
|
-
-
|
|
321
|
-
-
|
|
322
|
-
-
|
|
323
|
-
-
|
|
324
|
-
-
|
|
325
|
-
- `
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
|
344
|
-
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
1
|
+
# apick-api 한국어 가이드
|
|
2
|
+
|
|
3
|
+
## 스킬 성능표
|
|
4
|
+
|
|
5
|
+
`const { data } = await apick.getSkillPerformance()`로 [공개 측정표](https://apick.app/skills/performance)를 조회합니다. 표본 수·시험일·검사 방법·실패 사유를 함께 확인하세요. 모델 점수는 객관적 정확도가 아니며 미검증 값은 `null`입니다. 조회 자체에는 유료 실행이 필요하지 않습니다.
|
|
6
|
+
|
|
7
|
+
## 요청과 응답 형식
|
|
8
|
+
|
|
9
|
+
SDK의 본문 요청은 모두 `multipart/form-data`입니다. `utterance_ids[0]`처럼 배열을 개별 필드로 전송하며 `Content-Type` 헤더를 직접 지정할 필요가 없습니다. GET 조회는 본문을 보내지 않습니다. 기존 JSON 요청도 서버에서 호환용으로 계속 처리합니다.
|
|
10
|
+
|
|
11
|
+
SDK는 줄바꿈 문자열을 `__apick_encoding[필드]=base64-utf8` 메타 항목과 함께 보내 원문의 LF·CR을 보존합니다. Excel 셀은 타입 메타 항목을 함께 사용하며 Date는 ISO 문자열, 배열의 빈 칸은 null로 전달합니다.
|
|
12
|
+
|
|
13
|
+
응답은 서비스별 JSON 또는 파일입니다. 파일 다운로드 실패 시 JSON 오류가 반환될 수 있으며 SDK는 이를 `ApickApiError`로 전달합니다. 직접 REST를 연동할 때는 개발가이드의 OpenAPI 명세와 Postman 컬렉션을 내려받을 수 있습니다. MCP 외부 연결은 기존 JSON-RPC를 사용합니다.
|
|
14
|
+
|
|
15
|
+
`apick-api`는 에이픽의 주요 REST API를 Node.js에서 간단히 호출하기 위한 공식 SDK입니다. 런타임 의존성이 없으며 ESM, CommonJS, TypeScript를 지원합니다.
|
|
16
|
+
|
|
17
|
+
## 설치와 인증
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install apick-api
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { ApickClient } from 'apick-api';
|
|
25
|
+
|
|
26
|
+
const client = new ApickClient({
|
|
27
|
+
apiKey: process.env.APICK_API_KEY,
|
|
28
|
+
timeoutMs: 60_000
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
인증키는 생성자에만 전달하세요. 클라이언트 객체의 열거 가능한 속성에 저장되지 않으며 SDK가 로그로 출력하지 않습니다.
|
|
33
|
+
|
|
34
|
+
마이페이지의 허용 IP가 공란이면 제한 없이 호출할 수 있습니다. 제한하려면 APICK에 도착하는 공인 IPv4를 단일 주소 또는 CIDR(`/32` 등)로 등록하세요. 저장 즉시 반영되며 별도 동기화는 필요하지 않습니다.
|
|
35
|
+
|
|
36
|
+
## 조회와 검증
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
const business = await client.businessDetails('439-87-00761');
|
|
40
|
+
const venture = await client.ventureBusiness('4398700761');
|
|
41
|
+
const email = await client.validateEmail('sample@example.com');
|
|
42
|
+
const phone = await client.validatePhone('01012341234');
|
|
43
|
+
const holidays = await client.holidays(2026, 10);
|
|
44
|
+
const addresses = await client.searchAddress('가산디지털로', { page: 1 });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
사업자등록번호의 하이픈은 자동으로 제거합니다. 잘못된 필수값은 네트워크 요청 전에 `TypeError` 또는 `RangeError`로 차단합니다.
|
|
48
|
+
|
|
49
|
+
## 배송조회
|
|
50
|
+
|
|
51
|
+
택배사를 알면 지정조회가 더 정확합니다.
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const parcel = await client.trackParcel('cj', '123456789012');
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
택배사를 모르면 자동판별 조회를 사용할 수 있습니다.
|
|
58
|
+
|
|
59
|
+
```js
|
|
60
|
+
const parcel = await client.trackParcelAuto('123456789012');
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 도메인·검색
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
const dns = await client.dnsLookup('apick.app');
|
|
67
|
+
const location = await client.geolocate('apick.app');
|
|
68
|
+
const registration = await client.whois('apick.app');
|
|
69
|
+
const web = await client.googleSearch('에이픽 API', { page: 1 });
|
|
70
|
+
const images = await client.googleImageSearch('서울 야경', { page: 1 });
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## OCR
|
|
74
|
+
|
|
75
|
+
PNG와 JPEG를 지원하며 최대 크기는 50MB입니다.
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
const ocr = await client.ocr('./receipt.jpg');
|
|
79
|
+
console.log(ocr.data.result.full_text);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
메모리 데이터에는 파일명과 콘텐츠 타입을 지정할 수 있습니다.
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
await client.ocr(bytes, {
|
|
86
|
+
filename: 'scan.png',
|
|
87
|
+
contentType: 'image/png'
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## 파일 생성
|
|
92
|
+
|
|
93
|
+
현재 목소리는 `listGeminiTtsVoices()`와 `listOpenAiTtsVoices()`로 조회합니다. 기존 `TTS_VOICE_IDS`는 폐기된 목소리입니다.
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
정규화는 기본 켜짐이며 발음을 다듬는 스킬 요금이 추가됩니다. `normalize_text: false`(SDK `normalizeText: false`)로 실행과 요금을 끕니다. 스킬 최종가는 기본요금(판매자 금액·기본 수수료) + AI 원가 × 환율 × 1.4입니다. 정규화 실패는 제작을 중단하며, 서버·공급자의 최종 제작 실패는 정규화까지 전액 환불합니다. ASS에는 원문을 표시합니다.
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
const screenshot = await client.screenshot('https://example.com');
|
|
100
|
+
await screenshot.save('./example.jpeg');
|
|
101
|
+
|
|
102
|
+
// 유튜브 공개 영상: 영상 주소 또는 11자리 영상 ID
|
|
103
|
+
const video = await client.youtubeMetadata('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
|
|
104
|
+
const tracks = await client.youtubeSubtitleList(video.data.video_id);
|
|
105
|
+
const subtitle = await client.youtubeSubtitle(video.data.video_id, 'en', { format: 'srt' });
|
|
106
|
+
await subtitle.save('./' + subtitle.filename);
|
|
107
|
+
await (await client.youtubeThumbnail(video.data.video_id)).save('./thumbnail.jpg');
|
|
108
|
+
|
|
109
|
+
const created = await client.createTtsJob('오늘의 이야기를 시작합니다.', { voiceId: 'Kore' });
|
|
110
|
+
const jobId = created.data.job_id;
|
|
111
|
+
let job = await client.getTtsJob(jobId);
|
|
112
|
+
while (job.data.status === 'waiting' || job.data.status === 'processing') {
|
|
113
|
+
await new Promise(resolve => setTimeout(resolve, 3000));
|
|
114
|
+
job = await client.getTtsJob(jobId);
|
|
115
|
+
}
|
|
116
|
+
if (job.data.status === 'completed') {
|
|
117
|
+
const result = await client.downloadTtsResult(jobId);
|
|
118
|
+
await result.save(`./${jobId}.mp3`); // audio/mpeg, 1회만 다운로드 가능
|
|
119
|
+
const subtitles = await client.downloadTtsSubtitles(jobId);
|
|
120
|
+
await subtitles.save(`./${jobId}.ass`); // ASS 자막, 별도 1회 다운로드
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 취소는 waiting 또는 processing 상태에서 가능하며 이미 과금된 금액은 환불되지 않습니다.
|
|
124
|
+
// MP3와 ASS는 각각 다운로드 시작 시 해당 서버 원본이 즉시 폐기되어 재다운로드할 수 없습니다.
|
|
125
|
+
|
|
126
|
+
const pdf = await client.htmlToPdf('<h1>보고서</h1>', { pagination: true });
|
|
127
|
+
await pdf.save('./report.pdf');
|
|
128
|
+
|
|
129
|
+
const excel = await client.jsonToExcel([{ item: 'A', count: 3 }], {
|
|
130
|
+
sheetName: '재고'
|
|
131
|
+
});
|
|
132
|
+
await excel.save('./inventory.xlsx');
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
파일 결과에는 `bytes`, `size`, `filename`, `contentType`, `meta`가 포함됩니다. `save()`는 Node.js에서 파일을 저장하며, `toBlob()`은 웹 표준 `Blob`을 만듭니다.
|
|
136
|
+
|
|
137
|
+
## 텍스트 AI
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
const summary = await client.summarize(longText);
|
|
141
|
+
const polished = await client.polish(draftText);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
입력 텍스트는 최대 100,000자입니다.
|
|
145
|
+
|
|
146
|
+
## 이미지 AI
|
|
147
|
+
|
|
148
|
+
새 사용량 요금이 적용되면 외부 AI 판매가는 확인된 원가 × 적용 환율 × 1.4입니다. 생성·편집 응답에서 사용량이 미확정이면 HTTP 202와 `job_id`, `billing_status: "pending"`을 반환합니다. 이미 받은 결과는 보관하므로 재생성하지 말고 `getImageJob(job_id)`로 조회합니다. 정산 완료 후 기존 다운로드 메서드를 사용합니다.
|
|
149
|
+
|
|
150
|
+
```js
|
|
151
|
+
const result = await client.generateImages('흰 배경의 제품 사진', {
|
|
152
|
+
imageCount: 4,
|
|
153
|
+
size: '1024x1024',
|
|
154
|
+
outputFormat: 'webp',
|
|
155
|
+
idempotencyKey: 'product-draft-001'
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const referenceResult = await client.generateImages('제품 모양과 구도는 유지하고 배경을 햇살 좋은 주방으로 변경', {
|
|
159
|
+
referenceImage: './reference.png',
|
|
160
|
+
referenceFilename: 'reference.png',
|
|
161
|
+
referenceContentType: 'image/png'
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const job = await client.createImageGenerationJob('가로형 커버 시안', { imageCount: 20, size: '1536x1024' });
|
|
165
|
+
const status = await client.getImageJob(job.data.job_id);
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`imageCount`는 만들 이미지 장수이며 생략하면 1장입니다. 동기 생성·편집은 1~4장, 작업형 생성·편집은 1~50장입니다. 생성에 `referenceImage`를 함께 전달하면 참고 이미지의 구도·색감·제품 형태 등을 프롬프트와 조합할 수 있습니다. 편집은 50MB 이하의 PNG/JPEG/WebP 원본 이미지 한 장과 프롬프트를 받으며 마스크 파일은 지원하지 않습니다. 크기는 `1024x1024`, `1536x1024`, `1024x1536`, `1152x864`, `864x1152` 중에서 선택하고 프롬프트는 최대 28,000자까지 입력할 수 있습니다. 접수 시 이미지 장수×25포인트를 먼저 차감하며 실패한 이미지의 25포인트는 즉시 환급합니다. 접수된 작업은 취소할 수 없습니다. 결과 보관 기간은 완료 후 24시간입니다.
|
|
169
|
+
|
|
170
|
+
`idempotencyKey`는 같은 요청이 통신 오류로 두 번 전송됐을 때 중복 생성과 중복 과금을 막는 안전번호입니다. 영문·숫자·밑줄·하이픈으로 8~128자를 만들고, 같은 작업을 다시 보낼 때는 같은 값을 사용하세요. 프롬프트나 옵션이 달라진 새 작업에는 새 값을 사용해야 합니다.
|
|
171
|
+
|
|
172
|
+
지원 메서드: `generateImages`, `editImages`, `createImageGenerationJob`, `createImageEditJob`, `getImageJob`, `downloadImageJobImage`, `downloadImageJobArchive`.
|
|
173
|
+
|
|
174
|
+
## 응답 구조
|
|
175
|
+
|
|
176
|
+
JSON 메서드:
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
{
|
|
180
|
+
data: unknown;
|
|
181
|
+
meta: {
|
|
182
|
+
cost: number | null;
|
|
183
|
+
durationMs: number | null;
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`meta.cost`는 실제 응답에 포함된 차감 포인트입니다. API별 현재 요금은 에이픽 문서를 확인하세요.
|
|
189
|
+
|
|
190
|
+
## 신분증 마스킹
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
const png = await client.maskResidentNumber('./id-card.jpg', { type: 3 });
|
|
194
|
+
await png.save('./masked.png');
|
|
195
|
+
|
|
196
|
+
const result = await client.maskDriverLicense('./license.jpg');
|
|
197
|
+
console.log(result.data.result.fields);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
문서별 메서드는 `maskResidenceCard`, `maskPassport`, `maskIdCard`, `maskDriverLicense`입니다. 글자 판독 불가, 문서 불일치, 처리 실패는 각각 `IDENTITY_TEXT_UNREADABLE`, `IDENTITY_DOCUMENT_MISMATCH`, `IDENTITY_PROCESSING_FAILED`로 `ApickApiError.serviceCode`에 제공됩니다.
|
|
201
|
+
|
|
202
|
+
`maskResidenceCard`는 외국인등록증·영주증·외국국적동포 국내거소신고증의 앞면 한 장을 지원합니다. 영주증과 외국국적동포 국내거소신고증은 개인정보 마스킹만 지원하며 외국인등록증 진위확인 범위에는 포함되지 않습니다.
|
|
203
|
+
|
|
204
|
+
## 간편인증 데이터 조회
|
|
205
|
+
|
|
206
|
+
재직·소득·연금·면허·건강검진·현금영수증·국세 신고내역 조회는 본인 간편인증이 필요해 접수(`request*`)와 결과 조회(`get*`)가 나뉩니다.
|
|
207
|
+
|
|
208
|
+
아래 함수는 7종 모두에 공통으로 사용합니다. 같은 `transactionId`로 순차 조회하며 5→10→20→30초 간격으로 늘린 뒤 30초를 유지합니다. `resultAvailable === true`이면 즉시 결과를 반환합니다. `SUCCESS`는 전체 성공, `PARTIAL_SUCCESS`는 부분 성공이므로 `sources`에서 누락·실패 항목을 확인하세요. `AUTH_REJECTED`·`AUTH_EXPIRED`·`FAILED`는 실패 종료이며, `errorCode: 'RESULT_EXPIRED'`는 결과 보관 기간 만료입니다. 실패·만료 시 자동으로 재접수하지 않습니다.
|
|
209
|
+
|
|
210
|
+
<!-- simple-auth-polling:start -->
|
|
211
|
+
```js
|
|
212
|
+
async function pollDataResult(getResult, accepted, { timeoutMs = 600_000 } = {}) {
|
|
213
|
+
const pending = new Set([
|
|
214
|
+
'AUTH_REQUESTED', 'AUTH_WAITING', 'AUTH_COMPLETED', 'COLLECTING', 'COLLECTED'
|
|
215
|
+
]);
|
|
216
|
+
const failed = new Set(['AUTH_REJECTED', 'AUTH_EXPIRED', 'FAILED']);
|
|
217
|
+
const completed = new Set(['SUCCESS', 'PARTIAL_SUCCESS']);
|
|
218
|
+
const delays = [5_000, 10_000, 20_000, 30_000];
|
|
219
|
+
const deadline = Date.now() + timeoutMs;
|
|
220
|
+
const transactionId = accepted.data.transactionId;
|
|
221
|
+
const stop = code => { throw Object.assign(new Error(code), { code }); };
|
|
222
|
+
let response = accepted;
|
|
223
|
+
let attempt = 0;
|
|
224
|
+
|
|
225
|
+
for (;;) {
|
|
226
|
+
const data = response.data;
|
|
227
|
+
if (data.errorCode === 'RESULT_EXPIRED') stop('RESULT_EXPIRED');
|
|
228
|
+
if (failed.has(data.status)) stop(data.errorCode || data.status);
|
|
229
|
+
if (data.resultAvailable === true) {
|
|
230
|
+
if (data.result == null) stop('INVALID_RESULT');
|
|
231
|
+
return response;
|
|
232
|
+
}
|
|
233
|
+
if (completed.has(data.status)) stop('RESULT_NOT_AVAILABLE');
|
|
234
|
+
if (!pending.has(data.status)) stop('UNKNOWN_STATUS');
|
|
235
|
+
|
|
236
|
+
const awaitingApproval = ['AUTH_REQUESTED', 'AUTH_WAITING'].includes(data.status);
|
|
237
|
+
const authDeadline = Date.parse(data.expiresAt || accepted.data.expiresAt);
|
|
238
|
+
const limit = awaitingApproval && Number.isFinite(authDeadline)
|
|
239
|
+
? Math.min(deadline, authDeadline) : deadline;
|
|
240
|
+
const timeoutCode = awaitingApproval && limit === authDeadline
|
|
241
|
+
? 'AUTH_WAIT_TIMEOUT' : 'CLIENT_POLL_TIMEOUT';
|
|
242
|
+
const remaining = limit - Date.now();
|
|
243
|
+
if (remaining <= 0) stop(timeoutCode);
|
|
244
|
+
await new Promise(resolve => setTimeout(resolve,
|
|
245
|
+
Math.min(delays[Math.min(attempt++, delays.length - 1)], remaining)));
|
|
246
|
+
if (Date.now() >= limit) stop(timeoutCode);
|
|
247
|
+
response = await getResult(transactionId);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
<!-- simple-auth-polling:end -->
|
|
252
|
+
|
|
253
|
+
`AUTH_REQUESTED`·`AUTH_WAITING`은 사용자 승인을 기다리고, `AUTH_COMPLETED`·`COLLECTING`·`COLLECTED`는 결과가 준비될 때까지 계속 조회합니다. 과금 여부(`charged`, `success`)는 완료 기준이 아닙니다. 인증 대기에만 `expiresAt`을 적용하고 승인 후에는 전체 대기 한도를 적용합니다. 예제의 10분 한도는 클라이언트 정책이며, 진행 중인 호출의 제한 시간은 SDK의 `timeoutMs`로 별도 설정하세요. `AUTH_WAIT_TIMEOUT`·`CLIENT_POLL_TIMEOUT`·`RESULT_NOT_AVAILABLE`·`INVALID_RESULT`·`UNKNOWN_STATUS`는 예제에서 만드는 로컬 오류로, 응답 모순이나 알 수 없는 상태에서 무한 반복하지 않습니다. 통신 오류도 재시도 없이 호출자에게 전달합니다.
|
|
254
|
+
|
|
255
|
+
<!-- simple-auth-usage:start -->
|
|
256
|
+
```js
|
|
257
|
+
const accepted = await client.requestDrivingLicense({
|
|
258
|
+
name: '홍길동',
|
|
259
|
+
birthDate: '19900101',
|
|
260
|
+
phone: '01011112222',
|
|
261
|
+
authProvider: 'kakao'
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
try {
|
|
265
|
+
const result = await pollDataResult(id => client.getDrivingLicense(id), accepted);
|
|
266
|
+
if (result.data.status === 'PARTIAL_SUCCESS') console.warn(result.data.sources);
|
|
267
|
+
console.log(result.data.result);
|
|
268
|
+
} catch (error) {
|
|
269
|
+
if ((error.serviceCode || error.code) === 'RESULT_EXPIRED') {
|
|
270
|
+
console.error('결과 보관 기간 만료: 사용자 확인 후 새 인증을 요청하세요.');
|
|
271
|
+
} else {
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
<!-- simple-auth-usage:end -->
|
|
277
|
+
|
|
278
|
+
근거: [APICK 개발가이드](https://apick.app/dev_guide/data_health_checkup) · [MCP 3.5.0 상태 계약](https://github.com/lead788/apick-mcp/blob/a803abcb81d07377c85f49bb0b670baf0c17ed04/TOOLS.md)
|
|
279
|
+
|
|
280
|
+
`authProvider`는 `AUTH_PROVIDERS`(13종: kakao, naver, toss, pass, samsung, kb, shinhan, hana, woori, ibk, nh, kakaobank, banksalad) 중 하나입니다. 접수는 정액 과금, 결과는 최초 반환에서만 과금되며 재조회는 무료입니다. `requestEmployment`는 `insuranceYears`(1~3), `requestPersonalIncome`은 `incomeYears`(1~5), `requestNpsJoinHistory`는 `from`/`to`(`YYYY-MM`) 선택 입력을 받습니다. `requestCashReceiptDeduction`은 `incomeYears`(1~3), `requestTaxReturnHistory`는 `years`(1~10) 선택 입력을 받습니다. 나머지 상품은 `requestDrivingLicense`, `requestHealthCheckup`입니다.
|
|
281
|
+
|
|
282
|
+
## Skills
|
|
283
|
+
|
|
284
|
+
검수를 거친 Skill 을 검색하고 실행합니다. Skill 마다 입력 형식(`input_schema`)·결과 형식(`output_schema`)·기본 금액(`price_points`)이 정해져 있으며, 결과가 약속한 형식으로 반환된 실행만 차감됩니다.
|
|
285
|
+
|
|
286
|
+
생성형 AI 를 쓰는 Skill(`usage_priced: true`)은 기본 금액에 그 실행의 실제 사용량이 더해져 실행마다 금액이 달라집니다. `quoteSkill()` 은 예상 금액(`estimated_points`)과 최대 금액(`max_points`)을 돌려줍니다. 실행을 접수할 때 최대 금액을 예약하고, 끝나면 실제 금액만 차감한 뒤 나머지를 돌려줍니다. 실제 차감액은 `run.billing.charged_points` 에서 확인합니다.
|
|
287
|
+
|
|
288
|
+
```js
|
|
289
|
+
import { randomUUID } from 'node:crypto';
|
|
290
|
+
|
|
291
|
+
const found = await client.searchSkills({ query: '상품명', limit: 5 });
|
|
292
|
+
const skillId = found.data.items[0].skill_id;
|
|
293
|
+
const detail = await client.getSkill(skillId);
|
|
294
|
+
const input = { product_name: '튼튼한 접이식 우산' };
|
|
295
|
+
|
|
296
|
+
const quote = await client.quoteSkill(skillId, input); // 무료. 5분 동안 유효
|
|
297
|
+
const idempotencyKey = randomUUID(); // 재시도할 때 같은 값을 다시 씁니다
|
|
298
|
+
let run = (await client.runSkill(skillId, input, {
|
|
299
|
+
idempotencyKey, quoteId: quote.data.quote_id, maxCostPoints: quote.data.max_points
|
|
300
|
+
})).data;
|
|
301
|
+
while (!['succeeded', 'failed', 'timed_out', 'cancelled'].includes(run.status)) {
|
|
302
|
+
await new Promise(resolve => setTimeout(resolve, 2000));
|
|
303
|
+
run = (await client.getSkillRun(run.run_id)).data;
|
|
304
|
+
}
|
|
305
|
+
console.log(run.status, run.billing, run.result);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
| 메서드 | 설명 |
|
|
309
|
+
| --- | --- |
|
|
310
|
+
| `searchSkills({ query, category, sort, cursor, limit })` | 검색. `limit` 1~20, `category` 는 `SKILL_CATEGORIES`, `sort` 는 `SKILL_SORTS` 중 하나 |
|
|
311
|
+
| `getSkill(skillId)` | 입력·결과 형식, 가격, 처리 상한, 예제 |
|
|
312
|
+
| `quoteSkill(skillId, input, { version })` | 입력 검사와 차감될 포인트 확인. 실행하지 않습니다 |
|
|
313
|
+
| `runSkill(skillId, input, { idempotencyKey, quoteId, maxCostPoints, version, waitSeconds })` | 실행. `idempotencyKey` 필수, `waitSeconds` 0~20(기본 20) |
|
|
314
|
+
| `getSkillRun(runId)` / `getSkillRunResult(runId)` | 실행 상태(성공하면 결과 포함) / 결과만 조회. 결과는 7일 동안 보관 |
|
|
315
|
+
| `cancelSkillRun(runId)` | 끝나지 않은 실행 취소. 취소된 실행은 차감되지 않습니다 |
|
|
316
|
+
| `skillUsage({ cursor, limit })` | 내 실행 내역. `limit` 1~50 |
|
|
317
|
+
|
|
318
|
+
- `sort` 는 `recommended`(추천)·`popular`(인기)·`used`(많이 사용)·`likes`(좋아요순)·`rating`(평점순)·`new`(최신)·`mine`(내 계정이 많이 실행한 Skill)·`liked`(내 계정이 좋아요한 Skill) 가운데 하나입니다. 생략하면 등록 순서입니다.
|
|
319
|
+
- 검색·상세 응답에는 고를 때 참고하는 `usage_label`(사용 건수 구간: `1,000회 미만`, `1,000+`, `1만+` …), `like_count`, `review_count`, `rating_average`(1~5, 리뷰가 없으면 `null`)가 있습니다. 좋아요와 리뷰는 에이픽 웹의 Skill 화면에서 남깁니다.
|
|
320
|
+
- `sort` 는 `recommended`(추천)·`popular`(인기)·`used`(많이 사용)·`likes`(좋아요순)·`rating`(평점순)·`new`(최신)·`mine`(내 계정이 많이 실행한 Skill)·`liked`(내 계정이 좋아요한 Skill) 가운데 하나입니다. 생략하면 등록 순서입니다.
|
|
321
|
+
- 검색·상세 응답에는 고를 때 참고하는 `usage_label`(사용 건수 구간: `1,000회 미만`, `1,000+`, `1만+` …), `like_count`, `review_count`, `rating_average`(1~5, 리뷰가 없으면 `null`)가 있습니다. 좋아요와 리뷰는 에이픽 웹의 Skill 화면에서 남깁니다.
|
|
322
|
+
- Skills 응답은 봉투 없이 `data` 에 그대로 담기며, 과금 상태는 `data.billing.status`(`reserved`·`captured`·`released`·`partially_refunded`·`refunded`)로 확인합니다. `meta.cost` 는 채워지지 않습니다.
|
|
323
|
+
- 20초 안에 끝나지 않으면 `status` 가 `queued`·`running` 인 채로 돌아오므로 `getSkillRun` 으로 확인하세요.
|
|
324
|
+
- 응답을 받지 못했을 때는 같은 `idempotencyKey` 로 다시 호출하세요. 포인트는 한 번만 차감됩니다. 같은 키에 다른 입력을 보내면 `IDEMPOTENCY_CONFLICT` 입니다.
|
|
325
|
+
- 접수 전 거절은 `ApickApiError`(`serviceCode`: `INVALID_INPUT`·`INSUFFICIENT_POINTS`·`PAYMENT_REQUIRED`·`PRICE_EXCEEDS_LIMIT`·`RATE_LIMITED` 등, `details` 에 부가 정보)로, 접수 뒤 실패는 `status` 와 `failure_code`(`EXECUTION_FAILED`·`OUTPUT_INVALID`·`TIMED_OUT`·`CANCELLED`·`UPSTREAM_UNAVAILABLE`)로 확인합니다.
|
|
326
|
+
- `uses_generative_ai` 가 true 인 Skill 은 생성형 AI 로 결과를 만듭니다. 중요한 판단에 쓰기 전에 확인하세요.
|
|
327
|
+
|
|
328
|
+
## 오류와 재시도
|
|
329
|
+
|
|
330
|
+
`ApickApiError`에는 공개 오류 정보인 `code`, `serviceCode`, `status`, `message`가 포함됩니다. SDK는 중복 호출과 중복 과금을 방지하기 위해 자동 재시도를 하지 않습니다. 재시도가 필요하면 작업의 멱등성과 오류 코드를 확인한 뒤 애플리케이션에서 명시적으로 결정하세요.
|
|
331
|
+
## TTS 이전 버전에서 전환 / TTS migration
|
|
332
|
+
|
|
333
|
+
기존 APICK 목소리와 자동 전환은 종료되었습니다. `createTtsJob`은 Gemini 기본 목소리 `Kore`를 사용합니다. `getTtsQuality`, `retryTtsJob`, `downloadTtsCandidate`의 기존 경로는 HTTP 409를 반환합니다.
|
|
334
|
+
|
|
335
|
+
Legacy APICK voices and automatic fallback have retired. `createTtsJob` now defaults to Gemini voice `Kore`. The legacy quality, retry and candidate endpoints return HTTP 409.
|
|
336
|
+
|
|
337
|
+
## 영상 모델 버전 선택
|
|
338
|
+
|
|
339
|
+
`version`을 생략하면 Seedance 2.5, Veo 3.1, Kling 3.0을 사용합니다. 버전과 등급을 명시하면 해당 조합으로 생성하며 다른 모델로 자동 대체하지 않습니다. 생성과 상태 응답의 `version`으로 확인할 수 있습니다.
|
|
340
|
+
|
|
341
|
+
| 제품 | 제공 버전 | 제약과 요금 |
|
|
342
|
+
|---|---|---|
|
|
343
|
+
| Seedance | 2.5, 2.0(Standard·Fast·Mini), 1.5, 1.0 | [버전별 지원표](https://apick.app/dev_guide/seedancejobs) |
|
|
344
|
+
| Veo | 3.1 (Standard, Fast, Lite) | [버전별 지원표](https://apick.app/dev_guide/veojobs) |
|
|
345
|
+
| Kling | 3.0, O3, O1, 2.6, 2.5, 2.1, 2.0, 1.6 | [버전별 지원표](https://apick.app/dev_guide/klingjobs) |
|
|
346
|
+
|
|
347
|
+
등급·해상도·길이·오디오·파일 개수와 초당 포인트는 선택 조합별로 다릅니다. Seedance 2.0은 Standard·Fast·Mini를 제공하며 Mini는 480p·720p와 4~15초를 지원합니다. 무음 전용 모델은 `audio=false`, 오디오 필수 모델은 `audio=true`만 허용합니다. Veo 3.0은 현재 제공하지 않습니다. 지원하지 않는 조합은 접수 전에 거절됩니다.
|
|
348
|
+
|
|
349
|
+
Seedance 참조 소재 모드는 지원 버전에서 `referenceImages`, `referenceVideos`, `referenceAudios`(MP3·WAV)를 함께 사용할 수 있습니다.
|
|
350
|
+
|
|
351
|
+
```js
|
|
352
|
+
const job = await client.createVideoJob("kling", "A boat crossing the sea", {
|
|
353
|
+
version: "1.6", tier: "std", mode: "text", duration: 5, audio: false,
|
|
354
|
+
idempotencyKey: "boat-video-0001"
|
|
355
|
+
});
|
|
356
|
+
const status = await client.getVideoJob("kling", job.data.job_id);
|
|
357
|
+
if (status.data.status === "completed") {
|
|
358
|
+
await (await client.downloadVideoResult("kling", job.data.job_id)).save("boat.mp4");
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## 스킬 결과 파일과 실행 예상
|
|
363
|
+
|
|
364
|
+
스킬 상세·견적은 가격과 시간 범위, 도구별 예상 호출 수를 제공합니다. 실행 전 최대 예약액을 확인하고, 성공 결과의 파일은 인증이 적용되는 getSkillArtifact(runId, fileId)로 내려받으세요. 자세한 필드와 예시는 [스킬 결과 파일 안내](skill-artifacts.md)를 참고하세요.
|
|
365
|
+
|
|
366
|
+
## 상품별 조회 가이드
|
|
367
|
+
|
|
368
|
+
상품별 간편인증 조회 가이드에는 조회 데이터, 출처 기관, 활용 사례와 자주 묻는 질문이 있습니다. 인증 요청은 해당 상품의 자료를 조회하기 위한 단계이며 결과 조회용 transactionId를 반환합니다. 요청·응답 계약과 인증 방식은 동일합니다. [공통 인증 흐름](https://apick.app/dev_guide/data)에서 절차와 오류 처리를 확인하세요.
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
TTS: [Gemini·ChatGPT·정규화 / engines and normalization](tts.md). `createOpenAiTtsJob`, `listOpenAiTtsVoices`, `getTtsOptions`를 포함한 최신 계약입니다.
|