Bearer Token (Credits Auth)
Privy session JWTs and dial_live_* API keys for credits-mode endpoints.
Bearer Token (Credits Auth)
Credits-mode endpoints accept Authorization: Bearer … in two forms:
| Token | TTL | Best for |
|---|---|---|
Privy access token (eyJ…) | ~1 hour | Dashboard, browser apps with Privy SDK |
API key (dial_live_*) | Until revoked | Agents, cron, server scripts |
If you would rather pay per request without an account at all, skip Bearer and use x402 — most paid endpoints also accept on-chain USDC.
When to use Bearer (vs x402)
| You want… | Use |
|---|---|
| Pre-buy credits, then run scripts without re-signing each call | Bearer (Privy JWT or API key) |
| Stay account-less; pay per request from a funded wallet | x402 |
| Mix and match (script with credits, agent with wallet) | Either — dual-payment routes support both |
Internally the API resolves auth in this order (see
apps/web/lib/dual-payment.ts):
Authorization: Bearer <privy-access-token>orBearer dial_live_*→ debit credits.- No Bearer token → fall through to x402 (signed
PAYMENT-SIGNATURE). Authorization: Bearer <DIAL_ADMIN_API_KEY>→ operator bypass (no payment).
API keys are scope-gated per route. Privy sessions skip scope checks. See API Keys for the full scope table.
Get credentials from the dashboard
Open /dashboard/billing and sign in with Privy.
Permanent API key (recommended for Cursor, cron, bots)
- In API Keys · permanent bearer, click Quick: Cursor / agent key (or create a custom key).
- Copy the
dial_live_*secret once — it is shown only at creation. - Use
Authorization: Bearer dial_live_…— the key does not expire until you revoke it.
See API Keys.
Session token (quick curl only — ~1 hour)
- Scroll to Session token · short-lived (Privy JWT, starts with
eyJ…). - Click Reveal session token → Copy.
- Fine for a one-off test while the dashboard is open. Not for Cursor or long-running scripts.
The session token rotates every ~1 hour. Click Refresh after expiry.
Get a session token programmatically
If your app is already using the Privy SDK on
the same app.id as Dial, call getAccessToken():
import { usePrivy } from "@privy-io/react-auth";
function MyComponent() {
const { getAccessToken } = usePrivy();
const send = async () => {
const token = await getAccessToken();
if (!token) throw new Error("Sign in first");
await fetch("https://payphone.wtf/api/v1/sms/send", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ to: "+18148835337", message: "hi from credits" }),
});
};
}Server-side agents should prefer a dial_live_* API key instead of
embedding Privy refresh logic.
Use the token
Once you have a token, every credits-mode endpoint accepts it:
TOKEN="<paste-from-dashboard>"
curl -sS -X POST "https://payphone.wtf/api/v1/sms/send" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"to":"+18148835337","message":"Hello via credits"}'Sample success response:
{
"success": true,
"provider": "dial",
"messageId": "msg_…",
"to": "+18148835337",
"segments": 1
}If you have no credits left, you'll see:
{
"success": false,
"error": "insufficient_credits",
"credits": 0,
"required": 1
}(HTTP 402.) Top up via the dashboard or call
/api/v1/credits/top-up once with x402
to refill, then keep using the same Bearer token.
Check your balance
curl -sS "https://payphone.wtf/api/v1/account" \
-H "Authorization: Bearer $TOKEN"{
"privyUserId": "did:privy:cm…",
"credits": 9384,
"totalCredits": 9384,
"authMethod": "apikey",
"apiKeyPrefix": "abc12345"
}authMethod and apiKeyPrefix appear when authenticating with a
dial_live_* key so agents can confirm the correct credential.
Lifetime, refresh, revocation
| Credential | TTL | Revocation |
|---|---|---|
| Privy JWT | ~1 hour | Sign out of Privy |
dial_live_* API key | Until revoked | Revoke in /dashboard/billing |
- Privy refresh: the dashboard auto-refreshes via the Privy SDK while open.
Headless callers must call
getAccessToken()again after expiry. - API keys: no refresh needed; rotate by minting a new key and revoking the old prefix.
Security checklist
- Treat tokens and API keys like passwords. Anyone with the string can spend your credits until it expires or is revoked.
- Do not commit credentials to source control or paste them into chat threads.
- Prefer
dial_live_*keys for server-to-server agents over long-lived Privy JWT paste.
See also
- Getting Started — pick between Bearer and x402.
- API Keys — scopes and rotation.
/api/v1/credits/top-up— buy credits with x402.