openclaw-pine-voice 0.1.5 → 0.1.7

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/README.md CHANGED
@@ -87,11 +87,25 @@ Your agent now has access to the Pine Voice call tools.
87
87
 
88
88
  ### Step 3: Authenticate with Pine AI
89
89
 
90
- You have two options for when to authenticate:
90
+ **Option A: Just ask the agent (recommended)**
91
91
 
92
- **Option A: Authenticate now (recommended)**
92
+ The easiest way to authenticate is to simply tell your agent:
93
93
 
94
- We recommend authenticating right after installation. The auth flow requires an email verification code, so it's best done while you're actively setting things up not later when the agent tries to make a call (which could be at any time).
94
+ > "Set up Pine Voice authentication"
95
+
96
+ The agent will ask for your Pine AI email, send a verification code, ask you for the code, and save the credentials — all conversationally. It uses two built-in tools (`pine_voice_auth_request` and `pine_voice_auth_verify`) that handle the entire flow and write the credentials to `openclaw.json` automatically. After it's done, restart the gateway:
97
+
98
+ ```bash
99
+ openclaw gateway restart
100
+ ```
101
+
102
+ This also works on first use: if you skip authentication and later ask the agent to make a call, it will detect that credentials are missing and walk you through the same flow.
103
+
104
+ > **Note:** The verification code arrives by email, so you need to be available to provide it. If the agent tries to make a call while you're away, it will be blocked until you complete verification.
105
+
106
+ **Option B: Manual CLI setup**
107
+
108
+ If you prefer to authenticate from the terminal:
95
109
 
96
110
  ```bash
97
111
  # 1. Request a verification code (sent to your Pine AI account email)
@@ -101,13 +115,13 @@ openclaw pine-voice auth setup --email you@example.com
101
115
  openclaw pine-voice auth verify --email you@example.com --request-token <TOKEN> --code 1234
102
116
  ```
103
117
 
104
- The command prints your access token. Add it to your plugin config in `openclaw.json`:
118
+ The command prints your access token and user ID. Add them to your plugin config in `openclaw.json`:
105
119
 
106
120
  ```json
107
121
  {
108
122
  "plugins": {
109
123
  "entries": {
110
- "pine-voice": {
124
+ "openclaw-pine-voice": {
111
125
  "config": {
112
126
  "access_token": "PASTE_YOUR_TOKEN_HERE",
113
127
  "user_id": "PASTE_YOUR_USER_ID_HERE"
@@ -118,18 +132,12 @@ The command prints your access token. Add it to your plugin config in `openclaw.
118
132
  }
119
133
  ```
120
134
 
121
- Then restart the gateway again:
135
+ Then restart the gateway:
122
136
 
123
137
  ```bash
124
138
  openclaw gateway restart
125
139
  ```
126
140
 
127
- **Option B: Let the agent handle it on first use**
128
-
129
- If you skip authentication, the plugin still loads and the tool is visible to your agent. The first time the agent tries to make a call, it will receive an error explaining that authentication is needed. The agent will then guide you through the email verification flow — it will ask for your email, run the auth commands, and configure the token for you.
130
-
131
- This works, but keep in mind: the email verification code arrives in your inbox, so you need to be available to provide it. If the agent tries to make a call while you're away (e.g., in an automated workflow or overnight), it will be blocked until you complete verification.
132
-
133
141
  ## Try it out
134
142
 
135
143
  After setup, test that everything works by making a quick call to your own phone:
@@ -195,7 +203,7 @@ When using `pine_voice_call` + `pine_voice_call_status` (manual):
195
203
 
196
204
  | Error | Cause | Fix |
197
205
  |---|---|---|
198
- | TOKEN_EXPIRED | Access token expired | Re-run `openclaw pine-voice auth setup` |
206
+ | TOKEN_EXPIRED | Access token expired | Ask your agent to re-authenticate, or re-run `openclaw pine-voice auth setup` |
199
207
  | SUBSCRIPTION_REQUIRED | Not a Pro subscriber | Subscribe at 19pine.ai |
200
208
  | RATE_LIMITED | Too many calls | Wait and try again |
201
209
  | INSUFFICIENT_DETAIL | Objective too vague | Provide a more specific call objective |
package/dist/auth.d.ts CHANGED
@@ -1,7 +1,12 @@
1
1
  /**
2
2
  * Auth flow for Pine Voice plugin.
3
- * Registers CLI commands for email-based authentication.
3
+ *
4
+ * Provides two surfaces:
5
+ * 1. Tools (pine_voice_auth_request / pine_voice_auth_verify) — the primary,
6
+ * conversational path where the AI agent drives the flow.
7
+ * 2. CLI commands (openclaw pine-voice auth setup/verify) — a manual fallback.
4
8
  *
5
9
  * Delegates to the pine-voice SDK for actual API calls.
6
10
  */
11
+ export declare function registerAuthTools(api: any): void;
7
12
  export declare function registerAuthCommands(api: any): void;
package/dist/auth.js CHANGED
@@ -1,10 +1,145 @@
1
1
  /**
2
2
  * Auth flow for Pine Voice plugin.
3
- * Registers CLI commands for email-based authentication.
3
+ *
4
+ * Provides two surfaces:
5
+ * 1. Tools (pine_voice_auth_request / pine_voice_auth_verify) — the primary,
6
+ * conversational path where the AI agent drives the flow.
7
+ * 2. CLI commands (openclaw pine-voice auth setup/verify) — a manual fallback.
4
8
  *
5
9
  * Delegates to the pine-voice SDK for actual API calls.
6
10
  */
7
- import { PineVoice } from "pine-voice";
11
+ import { Type } from "@sinclair/typebox";
12
+ import { PineVoice, AuthError } from "pine-voice";
13
+ // ---------------------------------------------------------------------------
14
+ // Module-level state: stores requestToken between the request and verify steps
15
+ // so the AI agent never needs to pass it explicitly.
16
+ // ---------------------------------------------------------------------------
17
+ const pendingAuth = new Map(); // email → requestToken
18
+ // ---------------------------------------------------------------------------
19
+ // Tool registration (primary path)
20
+ // ---------------------------------------------------------------------------
21
+ export function registerAuthTools(api) {
22
+ // --- Tool: pine_voice_auth_request ---
23
+ api.registerTool({
24
+ name: "pine_voice_auth_request",
25
+ description: "Start Pine Voice authentication. Sends a verification code to the user's " +
26
+ "Pine AI account email. After calling this, ask the user to check their email " +
27
+ "(including spam) and provide the code, then call pine_voice_auth_verify.",
28
+ parameters: Type.Object({
29
+ email: Type.String({ description: "The user's Pine AI account email address" }),
30
+ }),
31
+ async execute(_toolCallId, params) {
32
+ try {
33
+ const { requestToken } = await PineVoice.auth.requestCode(params.email);
34
+ pendingAuth.set(params.email, requestToken);
35
+ api.log?.info?.(`pine-voice: auth code requested for ${params.email}`);
36
+ return {
37
+ content: [
38
+ {
39
+ type: "text",
40
+ text: `Verification code sent to ${params.email}. ` +
41
+ "Ask the user to check their email (including spam folder) and provide the code. " +
42
+ "Then call pine_voice_auth_verify with the email and code.",
43
+ },
44
+ ],
45
+ isError: false,
46
+ };
47
+ }
48
+ catch (err) {
49
+ const message = err instanceof Error ? err.message : String(err);
50
+ api.log?.error?.(`pine-voice: auth request failed: ${message}`);
51
+ const hint = err instanceof AuthError && err.status >= 400 && err.status < 500
52
+ ? " The email may not be registered — the user can sign up at https://19pine.ai."
53
+ : "";
54
+ return {
55
+ content: [{ type: "text", text: `Pine Voice auth request failed: ${message}.${hint}` }],
56
+ isError: true,
57
+ };
58
+ }
59
+ },
60
+ });
61
+ // --- Tool: pine_voice_auth_verify ---
62
+ api.registerTool({
63
+ name: "pine_voice_auth_verify",
64
+ description: "Complete Pine Voice authentication. Verifies the code the user received by email, " +
65
+ "saves the credentials to openclaw.json, and tells the user to restart the gateway. " +
66
+ "Must be called after pine_voice_auth_request.",
67
+ parameters: Type.Object({
68
+ email: Type.String({ description: "The same email used in pine_voice_auth_request" }),
69
+ code: Type.String({ description: "The verification code from the user's email" }),
70
+ request_token: Type.Optional(Type.String({ description: "Request token from pine_voice_auth_request (usually not needed — resolved automatically)" })),
71
+ }),
72
+ async execute(_toolCallId, params) {
73
+ const requestToken = params.request_token || pendingAuth.get(params.email);
74
+ if (!requestToken) {
75
+ return {
76
+ content: [
77
+ {
78
+ type: "text",
79
+ text: "No pending auth request found for this email. " +
80
+ "Call pine_voice_auth_request first to send a new verification code.",
81
+ },
82
+ ],
83
+ isError: true,
84
+ };
85
+ }
86
+ try {
87
+ const { accessToken, userId } = await PineVoice.auth.verifyCode(params.email, requestToken, params.code);
88
+ // Write credentials to openclaw.json
89
+ const cfg = api.runtime.config.loadConfig();
90
+ const plugins = (cfg.plugins ?? {});
91
+ const entries = (plugins.entries ?? {});
92
+ const pluginEntry = (entries["openclaw-pine-voice"] ?? {});
93
+ const updatedConfig = {
94
+ ...cfg,
95
+ plugins: {
96
+ ...plugins,
97
+ entries: {
98
+ ...entries,
99
+ "openclaw-pine-voice": {
100
+ ...pluginEntry,
101
+ config: {
102
+ ...(pluginEntry.config ?? {}),
103
+ access_token: accessToken,
104
+ user_id: userId,
105
+ },
106
+ },
107
+ },
108
+ },
109
+ };
110
+ await api.runtime.config.writeConfigFile(updatedConfig);
111
+ pendingAuth.delete(params.email);
112
+ api.log?.info?.(`pine-voice: auth successful for ${params.email}, credentials saved`);
113
+ return {
114
+ content: [
115
+ {
116
+ type: "text",
117
+ text: "Authentication successful! Credentials have been saved to openclaw.json. " +
118
+ "Tell the user to restart the gateway for the changes to take effect:\n\n" +
119
+ " openclaw gateway restart",
120
+ },
121
+ ],
122
+ isError: false,
123
+ };
124
+ }
125
+ catch (err) {
126
+ const message = err instanceof Error ? err.message : String(err);
127
+ api.log?.error?.(`pine-voice: auth verify failed: ${message}`);
128
+ const isExpired = message.toLowerCase().includes("expired");
129
+ const hint = isExpired
130
+ ? " The request token has expired — call pine_voice_auth_request again to send a new code."
131
+ : " Ask the user to double-check the code and try again.";
132
+ return {
133
+ content: [{ type: "text", text: `Pine Voice auth verification failed: ${message}.${hint}` }],
134
+ isError: true,
135
+ };
136
+ }
137
+ },
138
+ });
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // CLI registration (manual fallback)
142
+ // ---------------------------------------------------------------------------
8
143
  export function registerAuthCommands(api) {
9
144
  api.registerCli?.(({ program }) => {
10
145
  const pineVoice = program.command("pine-voice").description("Pine AI Voice Call plugin");
@@ -43,11 +178,11 @@ export function registerAuthCommands(api) {
43
178
  try {
44
179
  const { accessToken, userId } = await PineVoice.auth.verifyCode(opts.email, opts.requestToken || "", opts.code);
45
180
  console.log("Authentication successful!");
46
- console.log(`Add this to your pine-voice config in ~/.openclaw/openclaw.json:`);
181
+ console.log(`Add this to your plugin config in ~/.openclaw/openclaw.json:`);
47
182
  console.log("");
48
183
  console.log(` "plugins": {`);
49
184
  console.log(` "entries": {`);
50
- console.log(` "pine-voice": {`);
185
+ console.log(` "openclaw-pine-voice": {`);
51
186
  console.log(` "config": {`);
52
187
  console.log(` "access_token": "${accessToken}",`);
53
188
  console.log(` "user_id": "${userId}"`);
package/dist/index.d.ts CHANGED
@@ -4,7 +4,10 @@
4
4
  * Registers:
5
5
  * - pine_voice_call tool (initiate a phone call, returns immediately)
6
6
  * - pine_voice_call_status tool (check call progress / get results)
7
- * - pine-voice CLI commands (auth setup/verify)
7
+ * - pine_voice_call_and_wait tool (initiate + wait for result)
8
+ * - pine_voice_auth_request tool (start email-based auth)
9
+ * - pine_voice_auth_verify tool (complete auth and save credentials)
10
+ * - pine-voice CLI commands (auth setup/verify — manual fallback)
8
11
  *
9
12
  * Delegates all API calls to the pine-voice SDK. All safety, billing,
10
13
  * and prompt logic lives on Pine's side.
package/dist/index.js CHANGED
@@ -1,12 +1,15 @@
1
1
  import { registerVoiceCallTools } from "./tool.js";
2
- import { registerAuthCommands } from "./auth.js";
2
+ import { registerAuthTools, registerAuthCommands } from "./auth.js";
3
3
  /**
4
4
  * Pine AI Voice Call plugin for OpenClaw.
5
5
  *
6
6
  * Registers:
7
7
  * - pine_voice_call tool (initiate a phone call, returns immediately)
8
8
  * - pine_voice_call_status tool (check call progress / get results)
9
- * - pine-voice CLI commands (auth setup/verify)
9
+ * - pine_voice_call_and_wait tool (initiate + wait for result)
10
+ * - pine_voice_auth_request tool (start email-based auth)
11
+ * - pine_voice_auth_verify tool (complete auth and save credentials)
12
+ * - pine-voice CLI commands (auth setup/verify — manual fallback)
10
13
  *
11
14
  * Delegates all API calls to the pine-voice SDK. All safety, billing,
12
15
  * and prompt logic lives on Pine's side.
@@ -15,9 +18,11 @@ import { registerAuthCommands } from "./auth.js";
15
18
  * sessions_spawn so the main agent stays responsive during long calls.
16
19
  */
17
20
  export default function register(api) {
18
- // Register voice call tools (initiate + status)
21
+ // Register voice call tools (initiate + status + wait)
19
22
  registerVoiceCallTools(api);
20
- // Register CLI commands for authentication
23
+ // Register auth tools (conversational flow — primary)
24
+ registerAuthTools(api);
25
+ // Register CLI commands for authentication (manual fallback)
21
26
  registerAuthCommands(api);
22
27
  api.log?.info?.("pine-voice: plugin loaded");
23
28
  }
package/dist/tool.js CHANGED
@@ -2,38 +2,17 @@ import { Type } from "@sinclair/typebox";
2
2
  import { PineVoice, AuthError } from "pine-voice";
3
3
  /** Auth error message returned when credentials are missing. */
4
4
  const AUTH_MISSING_MESSAGE = [
5
- "Pine Voice is not authenticated yet. Both a user ID and access token are required before making calls.",
6
- "",
7
- "To set up authentication, run these commands in the terminal:",
8
- "",
9
- " # Step 1: Request a verification code (sent to your Pine AI account email)",
10
- " openclaw pine-voice auth setup --email <USER_EMAIL>",
11
- "",
12
- " # Step 2: Enter the code and request token from Step 1 to get your user ID and access token",
13
- " openclaw pine-voice auth verify --email <USER_EMAIL> --request-token <TOKEN> --code <CODE>",
14
- "",
15
- " # Step 3: Add both values to your plugin config in openclaw.json:",
16
- ' # plugins.entries.pine-voice.config.user_id = "<USER_ID>"',
17
- ' # plugins.entries.pine-voice.config.access_token = "<TOKEN>"',
18
- "",
19
- " # Step 4: Restart the gateway",
20
- " openclaw gateway restart",
21
- "",
22
- "Ask the user for their Pine AI account email to begin. If they don't have a Pine AI account, they can sign up at https://19pine.ai.",
5
+ "Pine Voice is not authenticated. To set up, use the pine_voice_auth_request tool",
6
+ "with the user's Pine AI email address. If they don't have an account, they can",
7
+ "sign up at https://19pine.ai.",
23
8
  ].join("\n");
24
9
  const AUTH_EXPIRED_MESSAGE = [
25
- "Pine Voice authentication has expired or is invalid.",
26
- "",
27
- "To re-authenticate, run:",
28
- " openclaw pine-voice auth setup --email <USER_EMAIL>",
29
- " openclaw pine-voice auth verify --email <USER_EMAIL> --request-token <TOKEN> --code <CODE>",
30
- "",
31
- "Then update user_id and access_token in openclaw.json and restart the gateway.",
32
- "Ask the user for their Pine AI account email to begin.",
10
+ "Pine Voice authentication has expired. Use pine_voice_auth_request with the",
11
+ "user's email to re-authenticate.",
33
12
  ].join("\n");
34
13
  /** Read plugin config and create a PineVoice SDK client. Returns error response if not authenticated. */
35
14
  function getClientOrError(api) {
36
- const config = api.config?.plugins?.entries?.["pine-voice"]?.config;
15
+ const config = api.config?.plugins?.entries?.["openclaw-pine-voice"]?.config;
37
16
  if (!config?.access_token || !config?.user_id) {
38
17
  return { content: [{ type: "text", text: AUTH_MISSING_MESSAGE }], isError: true };
39
18
  }
@@ -1,7 +1,7 @@
1
1
  {
2
- "id": "pine-voice",
2
+ "id": "openclaw-pine-voice",
3
3
  "name": "Pine AI Voice Call",
4
- "version": "0.1.5",
4
+ "version": "0.1.7",
5
5
  "description": "Make phone calls via Pine AI voice agent. The AI agent calls the specified number and carries out the conversation based on your instructions. The voice agent can only speak English, so calls can only be delivered to English-speaking countries. Before calling, gather all information the callee may need for authentication and verification — the agent cannot ask a human for missing info mid-call. Returns the full transcript. Powered by Pine AI.",
6
6
  "configSchema": {
7
7
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openclaw-pine-voice",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Make phone calls via Pine AI voice agent from OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,11 +1,8 @@
1
1
  ---
2
2
  name: pine-voice-auth
3
- description: Set up or refresh Pine Voice authentication. Obtains an access token via email verification and writes it to the plugin config.
3
+ description: Set up or refresh Pine Voice authentication via the built-in auth tools.
4
4
  metadata:
5
- {
6
- "openclaw":
7
- { "emoji": "🔑", "requires": { "bins": ["curl", "jq"] } },
8
- }
5
+ { "openclaw": { "emoji": "🔑" } }
9
6
  ---
10
7
 
11
8
  # Pine Voice Auth Setup
@@ -15,7 +12,7 @@ metadata:
15
12
  Use this skill when **any** of these are true:
16
13
 
17
14
  - The user asks to set up Pine Voice, configure Pine AI, or authenticate for voice calls
18
- - A `pine_voice_call` or `pine_voice_call_and_wait` invocation returns "Pine Voice is not authenticated yet"
15
+ - A `pine_voice_call` or `pine_voice_call_and_wait` invocation returns "Pine Voice is not authenticated"
19
16
  - A `pine_voice_call` or `pine_voice_call_and_wait` invocation fails with `TOKEN_EXPIRED`, `UNAUTHORIZED`, or a 401 response
20
17
  - The user says their Pine Voice token isn't working
21
18
 
@@ -24,7 +21,6 @@ Do **not** use this skill for making phone calls — see the `pine-voice` skill
24
21
  ## Prerequisites
25
22
 
26
23
  - The user must have a **Pine AI account** with a Pro subscription (sign up at https://19pine.ai)
27
- - `curl` and `jq` must be available in the shell
28
24
 
29
25
  ## Important: email verification requires user presence
30
26
 
@@ -32,16 +28,6 @@ This auth flow sends a verification code to the user's email inbox. The user **m
32
28
 
33
29
  **Recommended timing:** Run this flow right after plugin installation or when the user explicitly asks to set up Pine Voice — not during an unattended or automated workflow.
34
30
 
35
- ## Auth flow overview
36
-
37
- Pine Voice uses email-based verification. The flow has two API calls with a human step in between:
38
-
39
- 1. **Request** — send the user's email to get a `request_token`
40
- 2. **Wait** — user checks their email for a verification code
41
- 3. **Verify** — send email + request_token + code to get a `user_id` and `access_token`
42
- 4. **Store & restart** — write both values via `openclaw config set` and restart the gateway
43
- 5. **Test** — make a test call to verify everything works
44
-
45
31
  ## Step-by-step instructions
46
32
 
47
33
  ### Step 1: Ask the user for their Pine AI email
@@ -50,27 +36,15 @@ Ask: "What email address is your Pine AI account registered with?"
50
36
 
51
37
  Do not proceed until you have the email.
52
38
 
53
- ### Step 2: Request a verification code
39
+ ### Step 2: Send a verification code
54
40
 
55
- Run this command, replacing `USER_EMAIL` with the email from step 1:
41
+ Call the `pine_voice_auth_request` tool with the user's email:
56
42
 
57
- ```bash
58
- curl -s -X POST https://www.19pine.ai/api/v2/auth/email/request \
59
- -H "Content-Type: application/json" \
60
- -d '{"email": "USER_EMAIL"}' | jq .
61
43
  ```
62
-
63
- **Expected response:**
64
-
65
- ```json
66
- {"status": "success", "data": {"request_token": "abc123..."}}
44
+ pine_voice_auth_request({ email: "user@example.com" })
67
45
  ```
68
46
 
69
- Save the `request_token` valueyou need it in step 4.
70
-
71
- **If the request fails:**
72
- - `400` or `422` — the email may not be registered. Ask the user to check their email or sign up at https://19pine.ai.
73
- - Network error — check connectivity and retry.
47
+ This sends a verification code to their email. If the request fails with a 400/422, the email may not be registered ask the user to check their email or sign up at https://19pine.ai.
74
48
 
75
49
  ### Step 3: Ask the user for the verification code
76
50
 
@@ -78,53 +52,35 @@ Tell the user: "I've sent a verification code to your email. Please check your i
78
52
 
79
53
  Wait for the user to provide the code. Do not guess or skip this step.
80
54
 
81
- ### Step 4: Verify the code and obtain the access token
55
+ ### Step 4: Verify the code and save credentials
82
56
 
83
- Run this command, replacing `USER_EMAIL`, `THE_REQUEST_TOKEN`, and `THE_CODE` with the actual values:
57
+ Call the `pine_voice_auth_verify` tool with the email and code:
84
58
 
85
- ```bash
86
- curl -s -X POST https://www.19pine.ai/api/v2/auth/email/verify \
87
- -H "Content-Type: application/json" \
88
- -d '{"email": "USER_EMAIL", "request_token": "THE_REQUEST_TOKEN", "code": "THE_CODE"}' | jq .
89
59
  ```
90
-
91
- **Expected response:**
92
-
93
- ```json
94
- {"id": "1234567890", "access_token": "eyJ...", ...}
60
+ pine_voice_auth_verify({ email: "user@example.com", code: "123456" })
95
61
  ```
96
62
 
97
- Save **both** values:
98
- - **`id`** — the user's Pine user ID
99
- - **`access_token`** — the access token
63
+ The tool verifies the code, saves the credentials to `~/.openclaw/openclaw.json` automatically, and returns a success message.
100
64
 
101
65
  **If verification fails:**
102
- - `401` or `400` with "invalid code" — ask the user to double-check the code and try again.
103
- - `410` or "expired" the request_token expired. Go back to step 2 to start over.
66
+ - Invalid code — ask the user to double-check the code and try again (call `pine_voice_auth_verify` with the corrected code).
67
+ - Expired tokengo back to step 2 to send a new code.
104
68
 
105
- ### Step 5: Store the credentials and restart
69
+ ### Step 5: Restart the gateway
106
70
 
107
- Use `openclaw config set` to write both values to the OpenClaw config file (`~/.openclaw/openclaw.json`). Replace `THE_ACCESS_TOKEN` and `THE_USER_ID` with the actual values from step 4.
71
+ Tell the user to restart the gateway for the new credentials to take effect:
108
72
 
109
- **Important:** The user ID is all digits, so the CLI will parse it as a number unless you force it to be a JSON string with `--json` and explicit quotes.
73
+ "Credentials saved! Please run this command to activate them:"
110
74
 
111
- ```bash
112
- openclaw config set plugins.entries.pine-voice.config.access_token "THE_ACCESS_TOKEN"
113
- openclaw config set plugins.entries.pine-voice.config.user_id '"THE_USER_ID"' --json
114
- openclaw gateway restart
115
75
  ```
116
-
117
- You can verify the stored values with:
118
-
119
- ```bash
120
- openclaw config get plugins.entries.pine-voice.config
76
+ openclaw gateway restart
121
77
  ```
122
78
 
123
- **Note:** The config file is located at `~/.openclaw/openclaw.json`. The `plugins.entries.pine-voice.config` section should contain both `access_token` and `user_id`. The gateway **must be restarted** after updating the config for the new credentials to take effect.
79
+ The gateway **must be restarted** after authentication for the new credentials to take effect.
124
80
 
125
81
  ### Step 6: Verify with a test call
126
82
 
127
- After authentication is complete, suggest the user make a test call to their own phone number to verify everything works end-to-end:
83
+ After the gateway has restarted, suggest the user make a test call to their own phone number to verify everything works end-to-end:
128
84
 
129
85
  "Would you like to test it? I can call your phone to confirm everything is working. Just tell me your phone number."
130
86
 
@@ -145,6 +101,6 @@ Access tokens expire periodically. When a call fails with `TOKEN_EXPIRED` or a 4
145
101
 
146
102
  ## Security notes
147
103
 
148
- - Never log or echo the access token in plaintext beyond what is needed to write the config file
104
+ - Never log or echo the access token in plaintext beyond what is needed
149
105
  - The token is stored in a local config file with the same permissions as the user's home directory
150
106
  - Do not commit config files containing tokens to version control