Pine Voice API Reference
Integrate Pine voice calls directly into your application using the REST API or SDK. This API is for direct voice calls. For broader Pine Assistant sessions and tasks, use the Assistant API instead.
Base URLs
The API uses two hosts. Authentication goes through the Pine main API; voice call endpoints go through the gateway.
https://www.19pine.aihttps://agent3-api-gateway-staging.19pine.aiAll endpoints accept and return JSON. Include Content-Type: application/json in all requests.
Authentication
Pine Voice uses a two-step email verification flow to issue access tokens. Tokens are then passed as Bearer tokens in subsequent API calls.
Authentication flow
Request a verification code
Send your Pine account email to receive a one-time verification code via email.
Verify the code
Submit the code from your email along with the request_token. You get back an access_token and user_id.
Use credentials in API calls
Include both the access token and user ID as headers in all voice requests.
Required headers
Authorization: Bearer <access_token>
X-Pine-User-Id: <user_id>
Content-Type: application/jsonRequest Verification Code
Sends a one-time verification code to the provided email address. The email must be associated with an existing Pine account.
Request body
| Parameter | Type | Description |
|---|---|---|
| string | Your Pine account email address |
Example request
curl -X POST https://www.19pine.ai/api/v2/auth/email/request \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com"
}'Success response
{
"status": "success",
"data": {
"request_token": "eyJhbGciOiJIUzI1NiIs..."
}
}Verify Code & Get Token
Verifies the one-time code from your email and returns your access credentials. Store both access_token and id securely.
Request body
| Parameter | Type | Description |
|---|---|---|
| string | Same email used in the request step | |
| request_token | string | The request_token from the previous step |
| code | string | The verification code received via email |
Example request
curl -X POST https://www.19pine.ai/api/v2/auth/email/verify \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"request_token": "REQUEST_TOKEN",
"code": "1234"
}'Success response
{
"status": "success",
"data": {
"id": "1234567890",
"access_token": "eyJhbGciOiJSUzI1NiIs..."
}
}access_token securely. Do not commit it to version control or log it in plaintext.Initiate a Phone Call
Validates your request, runs safety and billing checks, and initiates a phone call using Pine's AI voice agent. The request blocks while the call is being set up, then returns a call_id.
Request body
| Parameter | Type | Description |
|---|---|---|
| dialed_number | string | Phone number to call in E.164 format, for example +14155551234. |
| callee_name | string | Name of the person or business being called. |
| callee_context | string | Background context about the callee. |
| call_objective | string | Clear, specific goal for the call. |
| detailed_instructions | string | Optional strategy, constraints, or fallback logic. |
| caller | "negotiator" | "communicator" | Optional. Defaults to negotiator. |
| voice | "male" | "female" | Optional. Defaults to female. |
| max_duration_minutes | integer | Optional. 1 to 120 minutes. Defaults to 120. |
| enable_summary | boolean | Optional. Request an LLM-generated summary after completion. |
Example request
curl -X POST https://agent3-api-gateway-staging.19pine.ai/api/v2/voice/call \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "X-Pine-User-Id: YOUR_USER_ID" \
-H "Content-Type: application/json" \
-d '{
"dialed_number": "+14155551234",
"callee_name": "Dr. Smith Office",
"callee_context": "Local dentist office, open Mon-Fri 9am-5pm",
"call_objective": "Schedule a dental cleaning appointment for next Tuesday afternoon",
"caller": "communicator",
"voice": "female",
"max_duration_minutes": 10
}'Success response
{
"call_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "in_progress"
}Caller Types: Negotiator vs Communicator
The caller parameter selects which Pine voice agent handles the call. Choosing the right type and providing the right level of detail is critical to call success.
Negotiator
Best for bill reductions, disputes, retention saves, contract renegotiations, and any call where the agent must defend a target outcome.
- Include target outcome, acceptable range, leverage points, and constraints.
- Good fit for adversarial or persuasive calls.
- Under-specified strategy usually produces poor results.
Communicator
Best for scheduling, reservations, confirmations, information requests, and straightforward operational calls.
- Provide context, preferences, and fallback options.
- Usually the right default for product workflows and testing.
- No hard negotiation strategy required.
negotiator, all strategy must be provided upfront in callee_context and detailed_instructions.Example: Negotiator call
{
"dialed_number": "+18005551234",
"callee_name": "Internet Provider Support",
"callee_context": "Current plan: 200 Mbps at $89.99/mo. Competitor offer: same speed at $49.99/mo.",
"call_objective": "Negotiate the monthly bill down from $89.99 to $60/mo or less",
"detailed_instructions": "Target: $60/mo. Acceptable range: up to $65/mo. Mention competitor offer as leverage. Do not change plan tier.",
"caller": "negotiator",
"voice": "male",
"max_duration_minutes": 30
}Example: Communicator call
{
"dialed_number": "+14155559876",
"callee_name": "The Italian Place",
"callee_context": "Italian restaurant on Main Street. Making a reservation for dinner.",
"call_objective": "Make a dinner reservation for 4 people tonight at 7pm",
"detailed_instructions": "If 7pm is not available, try 7:30 or 8pm. Prefer a booth if possible.",
"caller": "communicator",
"voice": "female",
"max_duration_minutes": 10
}Get Call Status
Poll this endpoint periodically until the call completes, or use SSE to wait for the final result instead. Once the call completes, the response includes the full transcript and optional summary.
Path parameters
| Parameter | Type | Description |
|---|---|---|
| call_id | string | The call_id returned from the initiate call endpoint |
Example request
curl https://agent3-api-gateway-staging.19pine.ai/api/v2/voice/call/CALL_ID \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "X-Pine-User-Id: YOUR_USER_ID"Response fields
| Field | Type | Description |
|---|---|---|
| call_id | string | Unique identifier for the call. |
| status | string | One of "in_progress", "completed", "failed", or "cancelled". |
| duration_seconds | number | Elapsed duration while running and after completion. |
| summary | string | Optional final summary when requested. |
| transcript | array | Full transcript after the call reaches a terminal state. |
| credits_charged | number | Credits billed for the completed call. |
Stream Call Status (SSE)
Opens a Server-Sent Events stream that waits for the final call result and delivers it as soon as it's available. This is the recommended alternative to polling.
result event after the call ends. It does not stream partial transcripts or live state changes.curl -N https://agent3-api-gateway-staging.19pine.ai/api/v2/voice/call/CALL_ID/stream \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "X-Pine-User-Id: YOUR_USER_ID" \
-H "Accept: text/event-stream"Quickstart
The easiest way to integrate Pine Voice is with the official SDKs. They handle authentication, request formatting, SSE result delivery with automatic polling fallback, and error handling for you.
Python
Sync and async support. Python 3.9+.
from pine_voice import PineVoice
request_token = PineVoice.auth.request_code("you@example.com")
credentials = PineVoice.auth.verify_code("you@example.com", request_token, "1234")
client = PineVoice(
access_token=credentials.access_token,
user_id=credentials.user_id,
)
result = client.calls.create_and_wait(
to="+14155551234",
name="Dr. Smith Office",
context="Local dentist office. Open Mon-Fri 9am-5pm.",
objective="Schedule a dental cleaning for next Tuesday afternoon",
caller="communicator",
)
print(result.status)
print(result.transcript)Node.js / TypeScript
Minimal setup for JS products and edge runtimes.
import { PineVoice } from "pine-voice";
const { requestToken } = await PineVoice.auth.requestCode("you@example.com");
const { accessToken, userId } = await PineVoice.auth.verifyCode(
"you@example.com",
requestToken,
"1234",
);
const client = new PineVoice({ accessToken, userId });
const result = await client.calls.createAndWait({
to: "+14155551234",
name: "Dr. Smith Office",
context: "Local dentist office. Open Mon-Fri 9am-5pm.",
objective: "Schedule a dental cleaning for next Tuesday afternoon",
caller: "communicator",
});
console.log(result.status);
console.log(result.transcript);Python SDK Reference
Full API reference for the pine-voice Python package. Supports both synchronous and asynchronous usage.
Constructor
| Argument | Type | Description |
|---|---|---|
| access_token | str | Required. Bearer token from the auth flow. |
| user_id | str | Required. Pine user ID used as X-Pine-User-Id. |
| gateway_url | str | Optional. Defaults to the staging gateway URL. |
Authentication
from pine_voice import PineVoice
request_token = PineVoice.auth.request_code("you@example.com")
credentials = PineVoice.auth.verify_code("you@example.com", request_token, "1234")calls.create_and_wait()
Initiates a call and blocks until it reaches a terminal state. Uses SSE first, with automatic polling fallback if streaming fails.
from pine_voice import PineVoice
request_token = PineVoice.auth.request_code("you@example.com")
credentials = PineVoice.auth.verify_code("you@example.com", request_token, "1234")
client = PineVoice(
access_token=credentials.access_token,
user_id=credentials.user_id,
)
result = client.calls.create_and_wait(
to="+14155551234",
name="Dr. Smith Office",
context="Local dentist office. Open Mon-Fri 9am-5pm.",
objective="Schedule a dental cleaning for next Tuesday afternoon",
caller="communicator",
)
print(result.status)
print(result.transcript)Errors
| Error class | When |
|---|---|
| PineVoiceError | Base class for all SDK errors. |
| AuthError | Authentication failures, missing credentials, expired tokens. |
| CallError | Call-specific failures such as invalid phone or policy rejection. |
| RateLimitError | Rate limit exceeded (429). |
Node.js / TypeScript SDK Reference
All core types are exported from pine-voice and available for import in TypeScript.
Constructor
| Argument | Type | Description |
|---|---|---|
| accessToken | string | Required. Bearer token from the auth flow. |
| userId | string | Required. Pine user ID used as X-Pine-User-Id. |
| gatewayUrl | string | Optional. Defaults to the staging gateway URL. |
Authentication
import { PineVoice } from "pine-voice";
const { requestToken } = await PineVoice.auth.requestCode("you@example.com");
const { accessToken, userId } = await PineVoice.auth.verifyCode("you@example.com", requestToken, "1234");calls.createAndWait()
Initiates a call and waits until it reaches a terminal state. Uses SSE first, with automatic polling fallback.
import { PineVoice } from "pine-voice";
const { requestToken } = await PineVoice.auth.requestCode("you@example.com");
const { accessToken, userId } = await PineVoice.auth.verifyCode(
"you@example.com",
requestToken,
"1234",
);
const client = new PineVoice({ accessToken, userId });
const result = await client.calls.createAndWait({
to: "+14155551234",
name: "Dr. Smith Office",
context: "Local dentist office. Open Mon-Fri 9am-5pm.",
objective: "Schedule a dental cleaning for next Tuesday afternoon",
caller: "communicator",
});
console.log(result.status);
console.log(result.transcript);Errors
| Error class | When |
|---|---|
| PineVoiceError | Base class for all SDK errors. |
| AuthError | Authentication failures, missing credentials, expired tokens. |
| CallError | Call-specific failures such as invalid phone or policy rejection. |
| RateLimitError | Rate limit exceeded (429). |
Error Codes
All errors follow a standard JSON response shape and include a machine-readable code plus HTTP status.
| Code | HTTP | Meaning |
|---|---|---|
| AUTH_REQUIRED | 401 | Missing or invalid Authorization or X-Pine-User-Id header. |
| TOKEN_EXPIRED | 401 | Access token expired. Repeat the email verification flow. |
| SUBSCRIPTION_REQUIRED | 403 | No active Pine subscription for this account. |
| INSUFFICIENT_CREDITS | 402 | Not enough credits to place a call. |
| INVALID_PHONE | 400 | Phone number is invalid or unsupported. |
| INSUFFICIENT_DETAIL | 400 | The objective or context is too vague for the agent to act. |
| RATE_LIMITED | 429 | Concurrent limits exceeded. |
| DND_BLOCKED | 403 | Target number is blocked by do-not-call controls. |
| POLICY_VIOLATION | 403 | Call rejected by policy or safety checks. |
| NOT_FOUND | 404 | The specified call_id does not exist. |
Rate Limits
Voice calls are English-only today. Supported phone regions include the US, Canada, Puerto Rico, UK, Australia, New Zealand, Singapore, Ireland, and Hong Kong. All numbers must be E.164 formatted.
5 concurrent calls
Per user, with a single-call max duration of 120 minutes.
Credits on terminal response
Completed call responses include credits_charged, so you can attribute usage inside your product.
Developer Preview
The surface will continue to evolve while we harden production workflows, pricing, and developer tooling.