Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/agent/asa-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Every `list` and `get` command in this file returns metadata only, no metrics. E

| Command | Flags | Notes |
|---|---|---|
| `asa whoami` | none | Company, how access was granted, Apple connection state. Run this first. No connected Apple Ads account or no active Ads Manager subscription answers `402 ads_manager_subscription_required` on every other `asa` command. |
| `asa whoami` | none | Company, how access was granted, Apple connection state. Run this first. Ads Manager access comes from the trial (`access_source: trial`) or a subscription (`payg`, `legacy`); without either, every other `asa` command answers `402 ads_manager_subscription_required`. |
| `asa connect` | `--no-wait` optional | Prints the Apple authorization link and waits for the link to be completed; `--no-wait` returns immediately instead of waiting. |
| `asa apps list` | pagination only | Apps promoted in Apple Search Ads. Its rows supply `--adam-id` for `campaigns create`. |
| `asa orgs list` | pagination only | Apple Search Ads organizations. Each row carries two identifiers, not interchangeable: `internal_id` (a UUID) and `org_id` (Apple's numeric id). `--org` on `campaigns create` takes `internal_id` — passing the numeric `org_id` fails with "Invalid org ID format." `payment_model` (`LOC`/`PAYG`) tells you whether campaigns in that organization need Invoicing Options — see [Line of credit](#line-of-credit-loc-organizations). |
Expand Down
2 changes: 1 addition & 1 deletion docs/agent/skills/adapty-cli-setup/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ the dashboard usually means the token is scoped elsewhere.
| `ERROR no_code_minted` | Login started but printed no code | Read `$TMPDIR/adapty-setup/auth.out` |
| `User code not found or expired` in the browser | The waiter died, or the TTL ran out | Step 1 again, and surface the new code faster |
| `AuthRequiredError` after `AUTHED` | Almost always a stale `ADAPTY_TOKEN` | `unset ADAPTY_TOKEN`, re-check |
| `402 ads_manager_subscription_required` | Authenticated fine; the company has no Ads Manager subscription | **Not a setup bug.** Say so plainly and stop. No flag works around it |
| `402 ads_manager_subscription_required` | Authenticated fine; the company has no Ads Manager access — neither the trial nor a subscription | **Not a setup bug.** Say so plainly and stop. No flag works around it |
| `NetworkError`, including certificate `-25291` noise | Network or sandbox trust-store access failed before authentication could be checked | Return to the caller's quiet preflight retry. Never install or log in |

## ADAPTY_TOKEN
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "adapty",
"description": "Adapty command line interface",
"version": "0.8.5",
"version": "0.8.6",
"author": "Adapty team <support@adapty.io>",
"bin": {
"adapty": "./bin/run.js"
Expand Down
5 changes: 3 additions & 2 deletions skills/adapty-cli/references/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@ There is no file-based hand-off flag: the config always rides in the URL.
## Apple Search Ads (`asa` topic)

Different service behind the same token. **No `--app`**: every command is scoped to the company the token
belongs to. Requires a connected Apple Ads account plus an active Ads Manager subscription — without one
every `asa` command answers `402 ads_manager_subscription_required`. Start with `asa whoami`.
belongs to. Requires a connected Apple Ads account plus Ads Manager access — the 14-day trial counts, same
as a paid subscription. Without access every `asa` command answers `402 ads_manager_subscription_required`.
Start with `asa whoami`: its `access_source` says which one granted access (`trial`, `payg`, `legacy`).

| Command | Required flags / notes |
|-------------------------------------|----------------------------------------------------------------------------|
Expand Down
9 changes: 7 additions & 2 deletions src/commands/asa/whoami.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@ grouped page may project to before it is refused.`;
}

if (result.access_source === 'none') {
this.log('\nNo active Ads Manager subscription for this company: connecting an account works, but every');
this.log('data command answers 402 until the subscription is in place.');
this.log('\nNo Ads Manager access for this company: connecting an account works, but every data command');
this.log('answers 402 until the Ads Manager trial is started or a subscription is in place.');
}

if (result.access_source === 'trial') {
this.log('\nAccess comes from the Ads Manager trial: every command works, and they stop working when');
this.log('the trial ends without a subscription.');
}

return result;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/asa-schemas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export type AsaAccessSource = 'allowlist' | 'legacy' | 'none' | 'payg';
export type AsaAccessSource = 'allowlist' | 'legacy' | 'none' | 'payg' | 'trial';

export type AsaAppleCredentialsStatus = 'active' | 'expired' | 'invalid' | 'unset';

Expand Down
11 changes: 10 additions & 1 deletion test/commands/asa.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,19 @@ describe('asa', () => {
fetchStub = mockFetch([{ ...ME_RESPONSE, access_source: 'none', apple_credentials_status: 'unset' }]);
const { stdout } = await runCommand('asa whoami');
expect(stdout).to.contain('Access Source: none');
expect(stdout).to.contain('No active Ads Manager subscription');
expect(stdout).to.contain('No Ads Manager access');
expect(stdout).to.contain('trial');
expect(stdout).to.contain('402');
});

it('whoami reports trial access and says it ends with the trial', async () => {
fetchStub = mockFetch([{ ...ME_RESPONSE, access_source: 'trial' }]);
const { stdout } = await runCommand('asa whoami');
expect(stdout).to.contain('Access Source: trial');
expect(stdout).to.contain('Ads Manager trial');
expect(stdout).to.not.contain('402');
});

it('whoami prints the budgets this company actually gets', async () => {
fetchStub = mockFetch([
{
Expand Down
Loading