apick-api 4.2.1 → 4.3.1

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 CHANGED
@@ -1,3 +1,14 @@
1
+ # 4.3.1
2
+
3
+ - Pricing notes (Terms art. 9 amended, effective 2026-11-06): TTS synthesis has a 5-point base fee per job and result-billed collection jobs have a 10-point base fee per job with results (Instagram comments 50). Fractional points are rounded up (0.1 → 1) and every billed use is at least 1 point. No method or type changes.
4
+ - 요금 안내 갱신(이용약관 제9조 개정, 2026-11-06 시행): TTS 합성 작업당 기본요금 5P, 결과 건수 과금 수집 작업은 결과가 있을 때 작업당 10P(인스타그램 댓글 50P)입니다. 포인트 계산의 소수점은 올림하며(0.1P → 1P) 과금되는 이용 1건은 최소 1P입니다. 메서드·타입 변경은 없습니다.
5
+ - 에이픽 에이전트(`apick-agent`) 안내: AI 사용 작업 기본 5P(2026-11-06부터), 캐시 재사용 1P로 표기를 실제 요금에 맞췄습니다. / `apick-agent` notes now match billing: 5-point base fee for AI jobs from 2026-11-06, cache reuse 1 point.
6
+
7
+ # 4.3.0
8
+
9
+ - Add `createGoogleMapsPlaceJob(placeIdOrUrl)` with the `GoogleMapsPlace` result type: rating, reviews count, 1-5 star distribution, top reviews (up to 10), opening hours, busy hours, similar places and photos. 20 points per place, refunded if not found; text is returned in English.
10
+ - 구글 지도 장소 상세·별점 분포·대표 리뷰(최대 10건) 조회 접수 메서드 `createGoogleMapsPlaceJob` 과 결과 타입 `GoogleMapsPlace` 를 추가했습니다. 건당 20포인트, 장소를 찾지 못하면 환불됩니다.
11
+
1
12
  # 4.2.1
2
13
 
3
14
  - `youtubeSubtitle()` fails with guidance to use an original-language track when an auto-translated caption (`translated: true`) is refused; such calls are not charged. Examples now pick a manual or original-language track. YouTube requests interrupted by a server restart are retried automatically.
package/README.md CHANGED
@@ -99,6 +99,7 @@ Leave the allowed-IP list blank for unrestricted access. To restrict access, reg
99
99
  | `createTiktokVideoJob(url, options)` | 틱톡 영상 정보 접수 / TikTok video job | JSON |
100
100
  | `createTiktokCommentsJob(url, options)` | 틱톡 댓글 수집 접수(최대 100) / TikTok comments job | JSON |
101
101
  | `createAmazonReviewsJob(urlOrAsin, options)` | 아마존 리뷰 수집 접수(최대 100) / Amazon reviews job | JSON |
102
+ | `createGoogleMapsPlaceJob(placeIdOrUrl, options)` | 구글 지도 장소 상세·별점 분포·대표 리뷰 접수 / Google Maps place details and top reviews job | JSON |
102
103
  | `getScrapeJob(jobId)` / `waitForScrapeJob(jobId, options)` | 수집 작업 상태·결과(무료, 결과 건수로 정산) / Collection job status and results | JSON |
103
104
  | `createTtsJob(text, options)` | 한국어 내레이션 작업 접수 / Create TTS job | JSON |
104
105
  | `getTtsJob(jobId)` | TTS 작업 상태 / TTS job status | JSON |
@@ -490,9 +491,9 @@ if (status.data.status === "completed") {
490
491
 
491
492
  ## 서브에이전트 / Subagent
492
493
 
493
- 설치형 `apick-agent` 상품은 `apick-subagent` 스킬 패키지와 전용 REST·MCP를 사용합니다. 원가 +40%, 승인된 동일 결과 캐시 무료, 충전 잔액 외 상품 한도 없음. [연동 가이드](https://apick.app/dev_guide/subagent).
494
+ 설치형 `apick-agent` 상품은 `apick-subagent` 스킬 패키지와 전용 REST·MCP를 사용합니다. 설치비·도입비·구독료 없이 원가 +40%(소수점 올림, 2026-11-06부터 AI 사용 작업 기본 5P), 승인된 동일 결과 캐시 1P, 충전 잔액 외 상품 한도 없음. [연동 가이드](https://apick.app/dev_guide/subagent).
494
495
 
495
- The installed `apick-agent` product uses the `apick-subagent` skill package and dedicated REST/MCP interfaces. Confirmed cost plus 40%; approved identical cache reuse is free, with no product quota beyond prepaid balance. [Integration guide](https://apick.app/dev_guide/subagent).
496
+ The installed `apick-agent` product uses the `apick-subagent` skill package and dedicated REST/MCP interfaces. No installation, setup or subscription fee. Confirmed cost plus 40% (fractions rounded up, 5-point base fee for AI jobs from 2026-11-06); approved identical cache reuse costs 1 point, with no product quota beyond prepaid balance. [Integration guide](https://apick.app/dev_guide/subagent).
496
497
 
497
498
  ```sh
498
499
  npx -y apick-mcp --server subagent
package/docs/guide.en.md CHANGED
@@ -96,6 +96,17 @@ const done = await client.waitForScrapeJob(job.data.job_id); // every 10 s, up t
96
96
  console.log(done.data.status, done.data.charged_point, done.data.items);
97
97
  ```
98
98
 
99
+ Result-billed collection jobs are charged per result; from 2026-11-06 a job with at least one result has a base fee (10 points, Instagram comments 50). Jobs with no results or failures are fully refunded.
100
+
101
+ For a Google Maps place, pass the `place_id` from `googleMapsSearch` to get details, the star distribution and top reviews (up to 10). 20 points per place; text is returned in English.
102
+
103
+ ```js
104
+ const places = await client.googleMapsSearch('cafes near Gangnam station');
105
+ const placeJob = await client.createGoogleMapsPlaceJob(places.data.items[0].place_id);
106
+ const place = await client.waitForScrapeJob(placeJob.data.job_id);
107
+ console.log(place.data.items[0].rating_distribution, place.data.items[0].top_reviews);
108
+ ```
109
+
99
110
  ## OCR
100
111
 
101
112
  OCR accepts PNG and JPEG files up to 50MB.
package/docs/guide.ko.md CHANGED
@@ -96,6 +96,17 @@ const done = await client.waitForScrapeJob(job.data.job_id); // 기본 10초 간
96
96
  console.log(done.data.status, done.data.charged_point, done.data.items);
97
97
  ```
98
98
 
99
+ 결과 건수 과금 수집 작업은 결과 1건당 단가로 정산하며, 2026-11-06부터 결과가 1건 이상이면 작업당 기본요금(10P, 인스타그램 댓글 50P)을 최소액으로 받습니다. 결과가 없거나 실패하면 예약한 포인트를 모두 돌려드립니다.
100
+
101
+ 구글 지도 장소는 `googleMapsSearch` 결과의 `place_id` 로 상세·별점 분포·대표 리뷰(최대 10건)를 받습니다. 건당 20포인트이고 텍스트는 영어로 제공합니다.
102
+
103
+ ```js
104
+ const places = await client.googleMapsSearch('강남역 카페');
105
+ const placeJob = await client.createGoogleMapsPlaceJob(places.data.items[0].place_id);
106
+ const place = await client.waitForScrapeJob(placeJob.data.job_id);
107
+ console.log(place.data.items[0].rating_distribution, place.data.items[0].top_reviews);
108
+ ```
109
+
99
110
  ## OCR
100
111
 
101
112
  PNG와 JPEG를 지원하며 최대 크기는 50MB입니다.
@@ -1,24 +1,24 @@
1
- # 스킬 결과 파일 · Skill artifacts
2
-
3
- 스킬 상세와 견적의 `execution_info`는 예상 가격 범위, 처리 시간 범위, 도구별 보통·최대 호출 수를 제공합니다. 실측 표본에 따른 예상이며 입력에 따라 달라집니다. 실행 전 견적의 `max_points`를 확인하세요.
4
-
5
- `execution_info` on Skill details and quotes describes estimated price and duration ranges and typical/maximum tool calls. These are estimates, not guarantees. Check `max_points` before running a Skill.
6
-
7
- ```js
8
- const quote = await apick.quoteSkill(skillId, input);
9
- console.log(quote.data.execution_info);
10
- const run = await apick.runSkill(skillId, input, {
11
- idempotencyKey: 'my-unique-request',
12
- quoteId: quote.data.quote_id,
13
- maxCostPoints: quote.data.max_points
14
- });
15
- // Poll getSkillRun until status is succeeded, then:
16
- const result = await apick.getSkillRunResult(run.data.run_id);
17
- const file = result.data.result.artifacts[0];
18
- const downloaded = await apick.getSkillArtifact(run.data.run_id, file.id);
19
- await downloaded.save('./result.png');
20
- ```
21
-
22
- 파일의 `name`, `mime_type`, `bytes`, `sha256`을 확인하고 실제 형식에 맞는 확장자로 저장하세요. 인증키 소유자의 실행 파일만 내려받을 수 있고, 실행 결과가 만료되면 파일도 만료됩니다. 실패·취소·시간 초과는 예약액을 반환하며, 가변 요금 상품은 성공 시 실제 사용료를 정산합니다. 공급자 청구서와 대조한 확정 원가를 뜻하지 않습니다.
23
-
24
- Use `name`, `mime_type`, `bytes`, and `sha256` to identify and verify each file; choose a matching extension. Downloads require the run owner's API key and expire with the result. Failed, cancelled, and timed-out runs release the reservation. Variable-price Skills settle recorded tool usage on success; calculated vendor costs are not invoice-reconciled amounts.
1
+ # 스킬 결과 파일 · Skill artifacts
2
+
3
+ 스킬 상세와 견적의 `execution_info`는 예상 가격 범위, 처리 시간 범위, 도구별 보통·최대 호출 수를 제공합니다. 실측 표본에 따른 예상이며 입력에 따라 달라집니다. 실행 전 견적의 `max_points`를 확인하세요.
4
+
5
+ `execution_info` on Skill details and quotes describes estimated price and duration ranges and typical/maximum tool calls. These are estimates, not guarantees. Check `max_points` before running a Skill.
6
+
7
+ ```js
8
+ const quote = await apick.quoteSkill(skillId, input);
9
+ console.log(quote.data.execution_info);
10
+ const run = await apick.runSkill(skillId, input, {
11
+ idempotencyKey: 'my-unique-request',
12
+ quoteId: quote.data.quote_id,
13
+ maxCostPoints: quote.data.max_points
14
+ });
15
+ // Poll getSkillRun until status is succeeded, then:
16
+ const result = await apick.getSkillRunResult(run.data.run_id);
17
+ const file = result.data.result.artifacts[0];
18
+ const downloaded = await apick.getSkillArtifact(run.data.run_id, file.id);
19
+ await downloaded.save('./result.png');
20
+ ```
21
+
22
+ 파일의 `name`, `mime_type`, `bytes`, `sha256`을 확인하고 실제 형식에 맞는 확장자로 저장하세요. 인증키 소유자의 실행 파일만 내려받을 수 있고, 실행 결과가 만료되면 파일도 만료됩니다. 실패·취소·시간 초과는 예약액을 반환하며, 가변 요금 상품은 성공 시 실제 사용료를 정산합니다. 공급자 청구서와 대조한 확정 원가를 뜻하지 않습니다.
23
+
24
+ Use `name`, `mime_type`, `bytes`, and `sha256` to identify and verify each file; choose a matching extension. Downloads require the run owner's API key and expire with the result. Failed, cancelled, and timed-out runs release the reservation. Variable-price Skills settle recorded tool usage on success; calculated vendor costs are not invoice-reconciled amounts.
package/docs/subagent.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # 서브에이전트 / Subagent
2
2
 
3
- `apick-agent`는 설치형 상품이며 `quoteSkill`·`runSkill` 대신 전용 API를 사용합니다. 성공 작업의 확인된 원가에 40%를 가산하며 승인된 동일 결과 캐시는 무료입니다. 충전 잔액 외 상품 사용량 한도는 없습니다.
3
+ `apick-agent`는 설치형 상품이며 `quoteSkill`·`runSkill` 대신 전용 API를 사용합니다. 설치비·도입비·구독료는 없고, 성공 작업의 확인된 원가에 40%를 가산합니다(소수점 올림, 2026-11-06부터 AI 사용 작업 기본 5P). 승인된 동일 결과 캐시는 1P입니다. 충전 잔액 외 상품 사용량 한도는 없습니다.
4
4
 
5
- `apick-agent` is an installed-agent product. Use the dedicated API rather than `quoteSkill` or `runSkill`. Successful work is billed at confirmed model cost plus 40%; approved identical-result cache reuse is free. There are no product usage quotas beyond prepaid balance.
5
+ `apick-agent` is an installed-agent product. Use the dedicated API rather than `quoteSkill` or `runSkill`. There is no installation, setup or subscription fee. Successful work is billed at confirmed model cost plus 40% (fractions rounded up, 5-point base fee for AI jobs from 2026-11-06); approved identical-result cache reuse costs 1 point. There are no product usage quotas beyond prepaid balance.
6
6
 
7
7
  ```js
8
8
  import { ApickClient } from 'apick-api';
package/docs/tts.md CHANGED
@@ -25,9 +25,9 @@ Style, emotion, tone, accent, pace, pitch and volume options can be set per requ
25
25
 
26
26
  Normalization is enabled by default and costs extra. Disable it with `normalize_text: false` (`normalizeText: false` for the string SDK helper). Input limits are 2,000 characters including utterance separators with normalization, or 8,000 without it. Query a quote, engine-specific voices and supported options before submitting.
27
27
 
28
- 실제 AI 원가 × 고정된 환율 × 1.4에 정규화 요금을 더해 정산합니다. Gemini 프로모션 입력/출력 단가는 2026-12-31까지 백만 토큰당 $0.50/$6.00이며 2027-01-01 00:00 UTC부터 $1.00/$12.00입니다. 약 $0.54/시간은 참고값이며 시간 단위 청구가 아닙니다. 엔진별 요금이 다릅니다.
28
+ 실제 AI 원가 × 고정된 환율 × 1.4에 정규화 요금을 더해 정산합니다. 소수점은 올림하며, 2026-11-06부터 합성 작업 1건의 기본요금 5P를 최소액으로 받습니다. Gemini 프로모션 입력/출력 단가는 2026-12-31까지 백만 토큰당 $0.50/$6.00이며 2027-01-01 00:00 UTC부터 $1.00/$12.00입니다. 약 $0.54/시간은 참고값이며 시간 단위 청구가 아닙니다. 엔진별 요금이 다릅니다.
29
29
 
30
- AI usage is charged at verified cost × the pinned exchange rate × 1.4, plus normalization. Gemini promotional input/output rates are $0.50/$6.00 per million tokens through 2026-12-31, then $1.00/$12.00 from 2027-01-01 00:00 UTC. The approximate hourly figure is informational; billing uses actual usage and differs by engine.
30
+ AI usage is charged at verified cost × the pinned exchange rate × 1.4, plus normalization. Fractions are rounded up, and from 2026-11-06 each synthesis job has a 5-point base fee. Gemini promotional input/output rates are $0.50/$6.00 per million tokens through 2026-12-31, then $1.00/$12.00 from 2027-01-01 00:00 UTC. The approximate hourly figure is informational; billing uses actual usage and differs by engine.
31
31
 
32
32
  두 엔진은 같은 작업 조회·취소·MP3·원문 ASS 계약을 사용합니다. `billing`의 예약·해제·확정·환불을 확인하세요. MP3는 24kHz 모노 48kbps, 결과는 완료 후 24시간 보관합니다. MP3와 ASS는 각각 완료된 다운로드 1회만 허용하며 전송 중단은 재시도할 수 있습니다. 접수 응답 유실 시 같은 입력과 멱등 키를 재사용하세요. 서버·공급자 최종 실패는 정규화까지 환불하며, 연결 종료는 작업 취소가 아닙니다. 취소 시 이미 수행된 작업분을 정산합니다.
33
33
 
@@ -1,10 +1,10 @@
1
- import { ApickClient } from 'apick-api';
2
-
3
- const client = new ApickClient(process.env.APICK_API_KEY);
4
-
5
- const business = await client.businessDetails('439-87-00761');
6
- console.log(business.data);
7
- console.log(business.meta);
8
-
9
- const parcel = await client.trackParcelAuto('123456789012');
10
- console.log(parcel.data);
1
+ import { ApickClient } from 'apick-api';
2
+
3
+ const client = new ApickClient(process.env.APICK_API_KEY);
4
+
5
+ const business = await client.businessDetails('439-87-00761');
6
+ console.log(business.data);
7
+ console.log(business.meta);
8
+
9
+ const parcel = await client.trackParcelAuto('123456789012');
10
+ console.log(parcel.data);
@@ -1,12 +1,12 @@
1
- const { ApickClient } = require('apick-api');
2
-
3
- async function main() {
4
- const client = new ApickClient(process.env.APICK_API_KEY);
5
- const result = await client.whois('apick.app');
6
- console.log(result.data);
7
- }
8
-
9
- main().catch((error) => {
10
- console.error(error.message);
11
- process.exitCode = 1;
12
- });
1
+ const { ApickClient } = require('apick-api');
2
+
3
+ async function main() {
4
+ const client = new ApickClient(process.env.APICK_API_KEY);
5
+ const result = await client.whois('apick.app');
6
+ console.log(result.data);
7
+ }
8
+
9
+ main().catch((error) => {
10
+ console.error(error.message);
11
+ process.exitCode = 1;
12
+ });
@@ -1,9 +1,9 @@
1
- import { ApickClient } from 'apick-api';
2
-
3
- const client = new ApickClient(process.env.APICK_API_KEY);
4
-
5
- const ocr = await client.ocr('./receipt.jpg');
6
- console.log(ocr.data.result.full_text);
7
-
8
- const pdf = await client.htmlToPdf('<h1>APICK report</h1>', { pagination: true });
9
- await pdf.save('./report.pdf');
1
+ import { ApickClient } from 'apick-api';
2
+
3
+ const client = new ApickClient(process.env.APICK_API_KEY);
4
+
5
+ const ocr = await client.ocr('./receipt.jpg');
6
+ console.log(ocr.data.result.full_text);
7
+
8
+ const pdf = await client.htmlToPdf('<h1>APICK report</h1>', { pagination: true });
9
+ await pdf.save('./report.pdf');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apick-api",
3
- "version": "4.2.1",
3
+ "version": "4.3.1",
4
4
  "description": "Official zero-dependency Node.js client for APICK data, AI, and image APIs. 에이픽 데이터·AI·이미지 API 공식 Node.js SDK.",
5
5
  "type": "module",
6
6
  "main": "./src/index.cjs",
package/src/form.cjs CHANGED
@@ -1,28 +1,28 @@
1
- 'use strict';
2
-
3
- // Client-only multipart serialization. Each value occupies its own form part.
4
- function createForm(payload, endpoint) {
5
- const form = new FormData();
6
- const typed = endpoint === '/rest/json_to_excel';
7
- const forbidden = new Set(['__proto__', 'prototype', 'constructor']);
8
- function visit(value, parts) {
9
- if (parts.some(key => forbidden.has(key) || /[\[\]]/.test(key)) || parts.length > 12) throw new TypeError('Invalid form field path.');
10
- const name = parts[0] + parts.slice(1).map(key => `[${key}]`).join('');
11
- const cell = typed && parts[0] === 'data_list';
12
- if (value === undefined || (value === null && !cell)) return;
13
- if (value instanceof Blob) { form.append(name, value); return; }
14
- if (value && typeof value === 'object' && Object.keys(value).length) {
15
- if (cell) form.append('__apick_type' + parts.map(key => `[${key}]`).join(''), Array.isArray(value) ? 'array' : 'object');
16
- for (const key of Object.keys(value)) visit(value[key], parts.concat(key));
17
- return;
18
- }
19
- if (cell && typeof value !== 'string') {
20
- form.append('__apick_type' + parts.map(key => `[${key}]`).join(''), value === null ? 'null' : Array.isArray(value) ? 'array' : typeof value);
21
- }
22
- if (!cell && value && typeof value === 'object') return;
23
- form.append(name, value === null || typeof value === 'object' ? '' : String(value));
24
- }
25
- for (const key of Object.keys(payload || {})) visit(payload[key], [key]);
26
- return form;
27
- }
28
- module.exports = { createForm };
1
+ 'use strict';
2
+
3
+ // Client-only multipart serialization. Each value occupies its own form part.
4
+ function createForm(payload, endpoint) {
5
+ const form = new FormData();
6
+ const typed = endpoint === '/rest/json_to_excel';
7
+ const forbidden = new Set(['__proto__', 'prototype', 'constructor']);
8
+ function visit(value, parts) {
9
+ if (parts.some(key => forbidden.has(key) || /[\[\]]/.test(key)) || parts.length > 12) throw new TypeError('Invalid form field path.');
10
+ const name = parts[0] + parts.slice(1).map(key => `[${key}]`).join('');
11
+ const cell = typed && parts[0] === 'data_list';
12
+ if (value === undefined || (value === null && !cell)) return;
13
+ if (value instanceof Blob) { form.append(name, value); return; }
14
+ if (value && typeof value === 'object' && Object.keys(value).length) {
15
+ if (cell) form.append('__apick_type' + parts.map(key => `[${key}]`).join(''), Array.isArray(value) ? 'array' : 'object');
16
+ for (const key of Object.keys(value)) visit(value[key], parts.concat(key));
17
+ return;
18
+ }
19
+ if (cell && typeof value !== 'string') {
20
+ form.append('__apick_type' + parts.map(key => `[${key}]`).join(''), value === null ? 'null' : Array.isArray(value) ? 'array' : typeof value);
21
+ }
22
+ if (!cell && value && typeof value === 'object') return;
23
+ form.append(name, value === null || typeof value === 'object' ? '' : String(value));
24
+ }
25
+ for (const key of Object.keys(payload || {})) visit(payload[key], [key]);
26
+ return form;
27
+ }
28
+ module.exports = { createForm };
package/src/index.cjs CHANGED
@@ -97,13 +97,19 @@ function profileInput(value) {
97
97
  return /^https?:\/\//i.test(text) ? { url: text } : { username: text.replace(/^@/, '') };
98
98
  }
99
99
 
100
+ // 구글 지도 장소 입력: 주소면 url, 아니면 place_id(googleMapsSearch 결과의 place_id)로 보낸다.
101
+ function placeInput(value) {
102
+ const text = requiredString('placeIdOrUrl', value, 2048);
103
+ return /^https?:\/\//i.test(text) ? { url: text } : { place_id: text };
104
+ }
105
+
100
106
  // 아마존 상품 입력: 주소면 url, 10자리 ASIN 이면 asin 으로 보낸다.
101
107
  function amazonInput(value) {
102
108
  const text = requiredString('urlOrAsin', value, 2048);
103
109
  return /^https?:\/\//i.test(text) ? { url: text } : { asin: text.toUpperCase() };
104
110
  }
105
111
 
106
- const SCRAPE_JOB_PRODUCTS = Object.freeze({ instagram_posts: 100, instagram_comments: 15, tiktok_search: 50, tiktok_video: 1, tiktok_comments: 100, amazon_reviews: 100 });
112
+ const SCRAPE_JOB_PRODUCTS = Object.freeze({ instagram_posts: 100, instagram_comments: 15, tiktok_search: 50, tiktok_video: 1, tiktok_comments: 100, amazon_reviews: 100, google_maps_place: 1 });
107
113
 
108
114
  // 수집 작업 공통 옵션: maxResults(상품별 상한), idempotencyKey(응답을 못 받아 다시 보낼 때 같은 접수로 처리).
109
115
  function scrapeJobOptions(product, payload, options) {
@@ -708,6 +714,11 @@ class ApickClient {
708
714
  return this._createScrapeJob('amazon_reviews', amazonInput(urlOrAsin), options);
709
715
  }
710
716
 
717
+ // 구글 지도 장소 상세·대표 리뷰(건당 고정가). 텍스트는 영어로 온다.
718
+ createGoogleMapsPlaceJob(placeIdOrUrl, options) {
719
+ return this._createScrapeJob('google_maps_place', placeInput(placeIdOrUrl), options);
720
+ }
721
+
711
722
  // 상태·결과 조회(무료). 끝난 작업은 실제 결과 건수로 정산돼 있다.
712
723
  getScrapeJob(jobId) {
713
724
  if (typeof jobId !== 'string' || !/^[a-f0-9]{32}$/.test(jobId)) throw new TypeError('jobId must be a 32-character job ID.');
package/src/index.d.ts CHANGED
@@ -194,7 +194,37 @@ export interface AmazonReview {
194
194
  readonly variant: string;
195
195
  }
196
196
 
197
- export type ScrapeJobProduct = "instagram_posts" | "instagram_comments" | "tiktok_search" | "tiktok_video" | "tiktok_comments" | "amazon_reviews";
197
+ export interface GoogleMapsPlace {
198
+ readonly name: string;
199
+ readonly category: string;
200
+ readonly categories: readonly string[];
201
+ readonly address: string;
202
+ readonly country_code: string;
203
+ readonly phone: string;
204
+ readonly website: string;
205
+ readonly description: string;
206
+ readonly rating: number | null;
207
+ readonly reviews_count: number | null;
208
+ /** 별점별 리뷰 수. */
209
+ readonly rating_distribution: Readonly<Record<"1" | "2" | "3" | "4" | "5", number | null>>;
210
+ /** 대표 리뷰(최대 10건). 작성자는 공개 표시 이름만. */
211
+ readonly top_reviews: readonly { readonly reviewer_name: string; readonly rating: number | null; readonly posted_at: string; readonly text: string }[];
212
+ readonly open_hours: Readonly<Record<string, string>>;
213
+ /** day: 1=월 … 7=일 */
214
+ readonly popular_times: readonly { readonly day: number | null; readonly hours: readonly { readonly hour: string; readonly busy_percent: number | null }[] }[];
215
+ readonly similar_places: readonly { readonly name: string; readonly category: string; readonly rating: number | null; readonly reviews_count: number | null }[];
216
+ readonly photo_urls: readonly string[];
217
+ readonly main_image_url: string;
218
+ readonly is_claimed: boolean;
219
+ readonly permanently_closed: boolean;
220
+ readonly temporarily_closed: boolean;
221
+ readonly latitude: number | null;
222
+ readonly longitude: number | null;
223
+ readonly place_id: string;
224
+ readonly map_url: string;
225
+ }
226
+
227
+ export type ScrapeJobProduct = "instagram_posts" | "instagram_comments" | "tiktok_search" | "tiktok_video" | "tiktok_comments" | "amazon_reviews" | "google_maps_place";
198
228
 
199
229
  export interface ScrapeJobOptions {
200
230
  /** 최대 결과 수. 이 수 × 단가를 예약하고 실제 결과 건수만 차감한다(instagram_comments 15, tiktok_search 50, 그 밖 100). */
@@ -624,6 +654,7 @@ export class ApickClient {
624
654
  createTiktokVideoJob(url: string, options?: Pick<ScrapeJobOptions, "idempotencyKey">): Promise<ApickResult<ScrapeJob<TiktokVideo>>>;
625
655
  createTiktokCommentsJob(url: string, options?: ScrapeJobOptions): Promise<ApickResult<ScrapeJob<SocialComment>>>;
626
656
  createAmazonReviewsJob(urlOrAsin: string, options?: ScrapeJobOptions): Promise<ApickResult<ScrapeJob<AmazonReview>>>;
657
+ createGoogleMapsPlaceJob(placeIdOrUrl: string, options?: Pick<ScrapeJobOptions, "idempotencyKey">): Promise<ApickResult<ScrapeJob<GoogleMapsPlace>>>;
627
658
  getScrapeJob<T = unknown>(jobId: string): Promise<ApickResult<ScrapeJob<T>>>;
628
659
  waitForScrapeJob<T = unknown>(jobId: string, options?: { intervalMs?: number; timeoutMs?: number }): Promise<ApickResult<ScrapeJob<T>>>;
629
660
  screenshot(url: string): Promise<ApickBinaryResult>;
package/src/index.js CHANGED
@@ -1,15 +1,15 @@
1
- import sdk from './index.cjs';
2
-
3
- export const {
4
- ApickClient,
5
- ApickApiError,
6
- ApickBinaryResult,
7
- SERVICES,
8
- TTS_VOICE_IDS,
9
- AUTH_PROVIDERS,
10
- SKILL_CATEGORIES,
11
- SKILL_SORTS,
12
- DEFAULT_BASE_URL
13
- } = sdk;
14
-
15
- export default ApickClient;
1
+ import sdk from './index.cjs';
2
+
3
+ export const {
4
+ ApickClient,
5
+ ApickApiError,
6
+ ApickBinaryResult,
7
+ SERVICES,
8
+ TTS_VOICE_IDS,
9
+ AUTH_PROVIDERS,
10
+ SKILL_CATEGORIES,
11
+ SKILL_SORTS,
12
+ DEFAULT_BASE_URL
13
+ } = sdk;
14
+
15
+ export default ApickClient;