@adkit/cli 1.12.20 → 1.12.22
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/dist/cli.js +122 -12
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1833,9 +1833,11 @@ var SEARCH_TERMS_FLAGS = ["campaign", "ad-group", "keyword", "keyword-match-type
|
|
|
1833
1833
|
var PLACEMENT_REPORT_FLAGS = ["campaign", "ad-group", "period", "from", "to", "sort", "limit", "raw"];
|
|
1834
1834
|
var GOOGLE_RESULTS_FLAGS = ["campaign", "ad-group", "period", "from", "to", "sort", "limit", "status", "breakdown", "fields", "conversion-actions", "raw"];
|
|
1835
1835
|
var GOOGLE_KEYWORD_RESULTS_FLAGS = ["campaign", "ad-group", "period", "from", "to", "sort", "limit", "status", "fields", "raw"];
|
|
1836
|
+
var CONVERSION_UPLOAD_FLAGS = ["conversion", "gclid", "gbraid", "wbraid", "occurred-at", "value", "currency", "order-id", "conversion-environment", "validate-only", "job-id"];
|
|
1836
1837
|
var CHANGE_HISTORY_FLAGS = ["account", "period", "from", "to", "limit", "resource", "campaign", "ad-group"];
|
|
1837
1838
|
var KEYWORD_RESEARCH_FLAGS = ["url", "location", "language", "limit", "min-volume"];
|
|
1838
1839
|
var TARGETING_RESEARCH_FLAGS = ["limit"];
|
|
1840
|
+
var NUMBER_FLAG_PATTERN = /^(?:\d+|\d+\.\d+|\.\d+)(?:e[+-]?\d+)?$/iu;
|
|
1839
1841
|
function generateCampaignName2() {
|
|
1840
1842
|
return `campaign ${getDateStamp()}`;
|
|
1841
1843
|
}
|
|
@@ -1961,6 +1963,51 @@ function buildGoogleMediaUploadSource(flags) {
|
|
|
1961
1963
|
if (name) source.name = name;
|
|
1962
1964
|
return source;
|
|
1963
1965
|
}
|
|
1966
|
+
function buildGoogleClickConversionUploadInput(flags) {
|
|
1967
|
+
const conversionId = requireSingleFlagValue(flags, "conversion", {
|
|
1968
|
+
missingHint: 'Run: adkit manage google conversions upload --conversion 123 --gclid <gclid> --occurred-at "2026-06-24 13:45:00+00:00" --value 120 --currency USD --validate-only'
|
|
1969
|
+
});
|
|
1970
|
+
const occurredAt = requireSingleFlagValue(flags, "occurred-at", {
|
|
1971
|
+
missingHint: 'Google offline uploads require a timestamp with timezone, e.g. "2026-06-24 13:45:00+00:00"'
|
|
1972
|
+
});
|
|
1973
|
+
const value = readNumberFlag(flags, "value", "Google offline uploads require --value <number>");
|
|
1974
|
+
const currency = requireSingleFlagValue(flags, "currency", {
|
|
1975
|
+
missingHint: "Google offline uploads require --currency <ISO code>, e.g. USD"
|
|
1976
|
+
});
|
|
1977
|
+
const conversion = {
|
|
1978
|
+
conversionId,
|
|
1979
|
+
occurredAt,
|
|
1980
|
+
value,
|
|
1981
|
+
currency
|
|
1982
|
+
};
|
|
1983
|
+
const gclid = readSingleFlagValue(flags, "gclid", "Use one --gclid value");
|
|
1984
|
+
const gbraid = readSingleFlagValue(flags, "gbraid", "Use one --gbraid value");
|
|
1985
|
+
const wbraid = readSingleFlagValue(flags, "wbraid", "Use one --wbraid value");
|
|
1986
|
+
const orderId = readSingleFlagValue(flags, "order-id", "Use one --order-id value");
|
|
1987
|
+
const conversionEnvironment = readSingleFlagValue(flags, "conversion-environment", "Use one --conversion-environment value");
|
|
1988
|
+
if (gclid) conversion.gclid = gclid;
|
|
1989
|
+
if (gbraid) conversion.gbraid = gbraid;
|
|
1990
|
+
if (wbraid) conversion.wbraid = wbraid;
|
|
1991
|
+
if (orderId) conversion.orderId = orderId;
|
|
1992
|
+
if (conversionEnvironment) conversion.conversionEnvironment = conversionEnvironment;
|
|
1993
|
+
return conversion;
|
|
1994
|
+
}
|
|
1995
|
+
function readNumberFlag(flags, key, hint) {
|
|
1996
|
+
const rawValue = requireSingleFlagValue(flags, key, { missingHint: hint });
|
|
1997
|
+
const trimmedValue = rawValue.trim();
|
|
1998
|
+
const value = NUMBER_FLAG_PATTERN.test(trimmedValue) ? Number(trimmedValue) : Number.NaN;
|
|
1999
|
+
if (!Number.isFinite(value) || value < 0) throw new CliError("INVALID_VALUE", `Invalid number for --${key}: ${rawValue}`, hint);
|
|
2000
|
+
return value;
|
|
2001
|
+
}
|
|
2002
|
+
function applyGoogleClickConversionUploadOptions(body, flags) {
|
|
2003
|
+
if (flags["validate-only"] === true) body.validateOnly = true;
|
|
2004
|
+
const rawJobId = readSingleFlagValue(flags, "job-id", "Use one --job-id value");
|
|
2005
|
+
if (!rawJobId) return;
|
|
2006
|
+
const trimmedJobId = rawJobId.trim();
|
|
2007
|
+
const jobId = /^\d+$/u.test(trimmedJobId) ? Number(trimmedJobId) : Number.NaN;
|
|
2008
|
+
if (!Number.isInteger(jobId) || jobId >= 2147483648) throw new CliError("INVALID_VALUE", `Invalid integer for --job-id: ${rawJobId}`, "Use a non-negative integer below 2147483648");
|
|
2009
|
+
body.jobId = jobId;
|
|
2010
|
+
}
|
|
1964
2011
|
function resolveAssetScope(flags) {
|
|
1965
2012
|
const scopeType = typeof flags.scope === "string" ? flags.scope : void 0;
|
|
1966
2013
|
if (scopeType !== "account" && scopeType !== "campaign" && scopeType !== "ad-group") throw new CliError("MISSING_FLAG", "Missing required flag: `--scope`", "Use --scope account|campaign|ad-group");
|
|
@@ -2301,6 +2348,24 @@ async function uploadMedia2(client, _args, flags) {
|
|
|
2301
2348
|
const path3 = `/manage/google/media${query}`;
|
|
2302
2349
|
return client.post(path3, body);
|
|
2303
2350
|
}
|
|
2351
|
+
async function uploadGoogleConversions(client, _args, flags) {
|
|
2352
|
+
validateFlags(flags, CONVERSION_UPLOAD_FLAGS, "manage google conversions upload");
|
|
2353
|
+
if (flags.publish === true) throw new CliError("INVALID_VALUE", "`--publish` is not used for conversion uploads", "Use --validate-only for a dry run; omit it to upload directly.");
|
|
2354
|
+
if (typeof flags.data === "string") {
|
|
2355
|
+
const rawBody = parseDataFlag(flags, 'Use { "conversions": [...] } for Google conversion upload');
|
|
2356
|
+
const accountId2 = resolveGoogleAccountId(rawBody, flags);
|
|
2357
|
+
const body2 = removeQueryOnlyBodyKeys(rawBody, ["accountId"]);
|
|
2358
|
+
const query2 = queryString({ accountId: accountId2 });
|
|
2359
|
+
const path4 = `/manage/google/conversions/upload${query2}`;
|
|
2360
|
+
return client.post(path4, body2);
|
|
2361
|
+
}
|
|
2362
|
+
const body = { conversions: [buildGoogleClickConversionUploadInput(flags)] };
|
|
2363
|
+
applyGoogleClickConversionUploadOptions(body, flags);
|
|
2364
|
+
const accountId = typeof flags.account === "string" ? flags.account : void 0;
|
|
2365
|
+
const query = queryString({ accountId });
|
|
2366
|
+
const path3 = `/manage/google/conversions/upload${query}`;
|
|
2367
|
+
return client.post(path3, body);
|
|
2368
|
+
}
|
|
2304
2369
|
async function listGoogleCampaigns(client, _args, flags) {
|
|
2305
2370
|
validateFlags(flags, CAMPAIGN_LIST_FLAGS, "manage google campaigns list");
|
|
2306
2371
|
const qs = buildGoogleListQuery(flags);
|
|
@@ -2843,7 +2908,7 @@ function readTikTokPlatformOverridesFlag(flags) {
|
|
|
2843
2908
|
function isCliTikTokPlatformOverrides(value) {
|
|
2844
2909
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
2845
2910
|
}
|
|
2846
|
-
function
|
|
2911
|
+
function readNumberFlag2(flags, key) {
|
|
2847
2912
|
const value = flags[key];
|
|
2848
2913
|
if (value === void 0) return void 0;
|
|
2849
2914
|
if (typeof value !== "string") throw new CliError("INVALID_VALUE", `Use one --${key} value`, `Run: adkit manage tiktok --help`);
|
|
@@ -2852,8 +2917,8 @@ function readNumberFlag(flags, key) {
|
|
|
2852
2917
|
return parsed;
|
|
2853
2918
|
}
|
|
2854
2919
|
function buildTikTokBudget(flags) {
|
|
2855
|
-
const daily =
|
|
2856
|
-
const lifetime =
|
|
2920
|
+
const daily = readNumberFlag2(flags, "budget-daily");
|
|
2921
|
+
const lifetime = readNumberFlag2(flags, "budget-lifetime");
|
|
2857
2922
|
if (daily === void 0 && lifetime === void 0) return void 0;
|
|
2858
2923
|
if (daily !== void 0 && lifetime !== void 0) throw new CliError("INVALID_VALUE", "Use either --budget-daily or --budget-lifetime", "TikTok accepts one budget mode per campaign/ad group");
|
|
2859
2924
|
return daily !== void 0 ? { daily } : { lifetime };
|
|
@@ -2898,7 +2963,7 @@ function buildTikTokAdGroupPayload(flags, mode) {
|
|
|
2898
2963
|
if (typeof flags["start-date"] === "string") payload.startDate = flags["start-date"];
|
|
2899
2964
|
if (typeof flags["end-date"] === "string") payload.endDate = flags["end-date"];
|
|
2900
2965
|
if (typeof flags.pacing === "string") payload.pacing = flags.pacing;
|
|
2901
|
-
const bidAmount =
|
|
2966
|
+
const bidAmount = readNumberFlag2(flags, "bid-amount");
|
|
2902
2967
|
if (bidAmount !== void 0) payload.bidAmount = bidAmount;
|
|
2903
2968
|
if (typeof flags["event-type"] === "string") {
|
|
2904
2969
|
payload.conversion = {
|
|
@@ -4753,7 +4818,7 @@ Notes:
|
|
|
4753
4818
|
With platformLocation, pass the exact Google geo object to send; AdKit does not look up or convert city names or addresses.
|
|
4754
4819
|
Google excludes support location geo target constants, not proximity radius exclusions.
|
|
4755
4820
|
Display campaign creation uses campaignType:"display" or --campaign-type display. Videos are not supported for Display media in v1.
|
|
4756
|
-
Performance Max: campaignType "performance_max" with exactly one assetGroups[] entry. Text assets inline ({role,text}); image assets are uploaded via google media first, then referenced by id/resourceName. Needs an enabled conversion
|
|
4821
|
+
Performance Max: campaignType "performance_max" with exactly one assetGroups[] entry. Text assets inline ({role,text}); image assets are uploaded via google media first, then referenced by id/resourceName. Needs an enabled conversion (publish is blocked without one). Non-retail only. Build it with --data.
|
|
4757
4822
|
View a Performance Max campaign by ID to read back assetGroups from Google. There is no separate google asset-groups command.
|
|
4758
4823
|
For spend/clicks/conversions: adkit manage google results
|
|
4759
4824
|
|
|
@@ -5302,6 +5367,33 @@ Notes:
|
|
|
5302
5367
|
Upload returns assets[].id and assets[].resourceName. Use either value in Display ad media[].id.
|
|
5303
5368
|
Display media roles: marketing_image, square_marketing_image, logo, square_logo.
|
|
5304
5369
|
Videos are not supported in Google Display v1; upload images only.`;
|
|
5370
|
+
var GOOGLE_CONVERSIONS_HELP = `adkit manage google conversions \u2014 Google Ads conversion tracking
|
|
5371
|
+
|
|
5372
|
+
upload Upload offline click conversion events
|
|
5373
|
+
|
|
5374
|
+
Flags (upload):
|
|
5375
|
+
--conversion <id> Google conversion ID (platformId), must be type upload_clicks
|
|
5376
|
+
--gclid <id> Google click ID
|
|
5377
|
+
--gbraid <id> GBRAID click parameter
|
|
5378
|
+
--wbraid <id> WBRAID click parameter
|
|
5379
|
+
--occurred-at <ts> Conversion timestamp with timezone, e.g. "2026-06-24 13:45:00+00:00"
|
|
5380
|
+
--value <n> Conversion value
|
|
5381
|
+
--currency <code> ISO currency code, e.g. USD
|
|
5382
|
+
--order-id <id> Optional order ID for dedupe/adjustments
|
|
5383
|
+
--conversion-environment <web|app>
|
|
5384
|
+
--validate-only Validate without importing conversions
|
|
5385
|
+
--job-id <n> Optional Google diagnostics job id
|
|
5386
|
+
--account <id> Optional if one Google Ads account is connected
|
|
5387
|
+
--data <json> Batch body: {"conversions":[...],"validateOnly":true}
|
|
5388
|
+
|
|
5389
|
+
Examples:
|
|
5390
|
+
adkit manage google conversions upload --conversion 123 --gclid EAIaIQob... --occurred-at "2026-06-24 13:45:00+00:00" --value 120 --currency USD --validate-only
|
|
5391
|
+
adkit manage google conversions upload --data '{"conversions":[{"conversionId":"123","gclid":"EAIaIQob...","occurredAt":"2026-06-24 13:45:00+00:00","value":120,"currency":"USD"}],"validateOnly":true}' --account 1234567890
|
|
5392
|
+
|
|
5393
|
+
Notes:
|
|
5394
|
+
Upload sends events directly to Google; it is not a draft flow.
|
|
5395
|
+
Use --validate-only before a real upload when testing a new CRM/backend export.
|
|
5396
|
+
Real uploads require publish access.`;
|
|
5305
5397
|
var META_RESEARCH_HELP = `adkit manage meta research \u2014 Meta Ads research tools
|
|
5306
5398
|
|
|
5307
5399
|
interests <query> Search targeting interests (returns IDs for ad set targeting)
|
|
@@ -5362,6 +5454,7 @@ Examples:
|
|
|
5362
5454
|
"google change-history": GOOGLE_CHANGE_HISTORY_HELP,
|
|
5363
5455
|
"google research": GOOGLE_RESEARCH_HELP,
|
|
5364
5456
|
"google media": GOOGLE_MEDIA_HELP,
|
|
5457
|
+
"google conversions": GOOGLE_CONVERSIONS_HELP,
|
|
5365
5458
|
"tiktok accounts": `adkit manage tiktok accounts \u2014 TikTok Ads accounts
|
|
5366
5459
|
|
|
5367
5460
|
list List connected TikTok advertisers
|
|
@@ -5537,7 +5630,7 @@ Examples:
|
|
|
5537
5630
|
|
|
5538
5631
|
Bypasses normalized AdKit entity validation, but still runs account and safety checks.
|
|
5539
5632
|
GET requests execute immediately. POST/PATCH/DELETE create drafts by default; add --publish to execute mutating requests immediately.
|
|
5540
|
-
Must be enabled in
|
|
5633
|
+
Must be enabled in Agent Permissions first.
|
|
5541
5634
|
Use this for unsupported native platform resources/workflows. Use platformOverrides instead when you only need raw fields on a supported normalized resource.
|
|
5542
5635
|
Use the selected platform's official endpoint paths, field names, enum values, and resource shapes. Do not translate normalized AdKit field names into raw API payloads by guessing.
|
|
5543
5636
|
|
|
@@ -5604,6 +5697,7 @@ Entity groups:
|
|
|
5604
5697
|
ads Manage responsive search and Display ads
|
|
5605
5698
|
keywords Manage keywords and negatives \u2014 config only, not metrics
|
|
5606
5699
|
keywords negative-lists Shared negative keyword lists (create, attach to campaigns)
|
|
5700
|
+
conversions Manage conversion tracking and upload offline conversions
|
|
5607
5701
|
results Performance metrics (campaigns, ad-groups, ads, keywords, search-terms)
|
|
5608
5702
|
change-history Recent Google Ads account changes from the last 30 days
|
|
5609
5703
|
research Keyword Planner plus Display topic/interest IDs
|
|
@@ -5615,7 +5709,8 @@ ${FLAG.account}
|
|
|
5615
5709
|
${FLAG.publish}
|
|
5616
5710
|
${FLAG.data}
|
|
5617
5711
|
|
|
5618
|
-
|
|
5712
|
+
Config mutations are draft-first by default. Use --publish to publish immediately.
|
|
5713
|
+
Conversion uploads send events directly; use --validate-only for a dry run.
|
|
5619
5714
|
${rawPlatformCommandLine("google")}
|
|
5620
5715
|
Display path: research topics/interests, upload images with google media, create campaigns --campaign-type display, create ad-groups with targeting, then create ads with type:"responsive_display".
|
|
5621
5716
|
Google Display Ads is in beta \u2014 some first-class normalized Display features may not be available yet.
|
|
@@ -5901,6 +5996,7 @@ var HELP_FULL = {
|
|
|
5901
5996
|
"google change-history": GOOGLE_CHANGE_HISTORY_HELP,
|
|
5902
5997
|
"google research": GOOGLE_RESEARCH_HELP,
|
|
5903
5998
|
"google media": GOOGLE_MEDIA_HELP,
|
|
5999
|
+
"google conversions": GOOGLE_CONVERSIONS_HELP,
|
|
5904
6000
|
"meta research": META_RESEARCH_HELP,
|
|
5905
6001
|
"studio generate": STUDIO_GENERATE_HELP_FULL,
|
|
5906
6002
|
"library advertisers": `adkit library advertisers \u2014 Browse, inspect, and discover advertisers
|
|
@@ -6817,7 +6913,7 @@ async function main() {
|
|
|
6817
6913
|
case "list":
|
|
6818
6914
|
case void 0:
|
|
6819
6915
|
data = await listAccounts(client, restArgs, flags);
|
|
6820
|
-
emptyHint = "No Meta ad accounts connected. Run `adkit setup manage` or connect via https://app.adkit.so/settings/integrations";
|
|
6916
|
+
emptyHint = "No Meta ad accounts connected. Run `adkit setup manage` or connect a workspace login via https://app.adkit.so/dashboard/settings/workspace-integrations";
|
|
6821
6917
|
break;
|
|
6822
6918
|
case "connect":
|
|
6823
6919
|
data = await connectAccount(client, restArgs, flags);
|
|
@@ -6988,7 +7084,7 @@ async function main() {
|
|
|
6988
7084
|
case "list":
|
|
6989
7085
|
case void 0:
|
|
6990
7086
|
data = await listAccounts2(client, restArgs, flags);
|
|
6991
|
-
emptyHint = "No Google Ads accounts connected. Run `adkit setup manage` or connect via https://app.adkit.so/settings/integrations";
|
|
7087
|
+
emptyHint = "No Google Ads accounts connected. Run `adkit setup manage` or connect a workspace login via https://app.adkit.so/dashboard/settings/workspace-integrations";
|
|
6992
7088
|
break;
|
|
6993
7089
|
case "available":
|
|
6994
7090
|
data = await listAvailable(client, restArgs, flags);
|
|
@@ -7220,6 +7316,20 @@ async function main() {
|
|
|
7220
7316
|
else data = await listGoogleResults(client, restArgs, flags);
|
|
7221
7317
|
break;
|
|
7222
7318
|
}
|
|
7319
|
+
case "conversions": {
|
|
7320
|
+
if (!action || flags.help) {
|
|
7321
|
+
showHelp("google conversions", flags.help === "full");
|
|
7322
|
+
process.exit(0);
|
|
7323
|
+
}
|
|
7324
|
+
switch (action) {
|
|
7325
|
+
case "upload":
|
|
7326
|
+
data = await uploadGoogleConversions(client, restArgs, flags);
|
|
7327
|
+
break;
|
|
7328
|
+
default:
|
|
7329
|
+
throw new CliError("UNKNOWN_COMMAND", `Unknown action: google conversions ${action}`, "Available: upload");
|
|
7330
|
+
}
|
|
7331
|
+
break;
|
|
7332
|
+
}
|
|
7223
7333
|
case "change-history": {
|
|
7224
7334
|
if (action && action !== "list") throw new CliError("UNKNOWN_COMMAND", `Unknown action: google change-history ${action}`, "Available: list");
|
|
7225
7335
|
data = await listGoogleChangeHistory(client, restArgs, flags);
|
|
@@ -7246,7 +7356,7 @@ async function main() {
|
|
|
7246
7356
|
break;
|
|
7247
7357
|
}
|
|
7248
7358
|
default:
|
|
7249
|
-
throw new CliError("UNKNOWN_COMMAND", `Unknown entity: google ${entity}`, "Available: accounts, assets, media, campaigns, ad-groups, ads, keywords, results, change-history, research");
|
|
7359
|
+
throw new CliError("UNKNOWN_COMMAND", `Unknown entity: google ${entity}`, "Available: accounts, assets, media, campaigns, ad-groups, ads, keywords, conversions, results, change-history, research");
|
|
7250
7360
|
}
|
|
7251
7361
|
} else if (platform2 === "tiktok") {
|
|
7252
7362
|
switch (entity) {
|
|
@@ -7255,7 +7365,7 @@ async function main() {
|
|
|
7255
7365
|
case "list":
|
|
7256
7366
|
case void 0:
|
|
7257
7367
|
data = await listTikTokAccounts(client, restArgs, flags);
|
|
7258
|
-
emptyHint = "No TikTok Ads accounts connected. Run `adkit setup manage` or connect via https://app.adkit.so/settings/integrations";
|
|
7368
|
+
emptyHint = "No TikTok Ads accounts connected. Run `adkit setup manage` or connect a workspace login via https://app.adkit.so/dashboard/settings/workspace-integrations";
|
|
7259
7369
|
break;
|
|
7260
7370
|
case "available":
|
|
7261
7371
|
data = await listTikTokAvailableAccounts(client, restArgs, flags);
|
|
@@ -7372,7 +7482,7 @@ async function main() {
|
|
|
7372
7482
|
case "list":
|
|
7373
7483
|
case void 0:
|
|
7374
7484
|
data = await listRedditAccounts(client, restArgs, flags);
|
|
7375
|
-
emptyHint = "No Reddit Ads accounts connected. Run `adkit setup manage` or connect via https://app.adkit.so/settings/integrations";
|
|
7485
|
+
emptyHint = "No Reddit Ads accounts connected. Run `adkit setup manage` or connect a workspace login via https://app.adkit.so/dashboard/settings/workspace-integrations";
|
|
7376
7486
|
break;
|
|
7377
7487
|
case "available":
|
|
7378
7488
|
data = await listRedditAvailableAccounts(client, restArgs, flags);
|
package/package.json
CHANGED