DEV Community

Cover image for Sinch from the Command Line: Numbers, Calls, Messages, Logs
Gunnar Grosch
Gunnar Grosch

Posted on

Sinch from the Command Line: Numbers, Calls, Messages, Logs

In my previous post on Sinch Functions, I kept reaching for the CLI to test things. At some point I realized I'd been treating @sinch/cli as a Functions tool when it actually covers the whole product surface: numbers, voice, messaging, fax, SIP trunking, porting. This post goes wider.

You can do a lot with the Sinch CLI before you've written a line of application code. No Postman, no dashboard tab-switching.

The sections below are independent: different prerequisites, different credentials, no assumed order. Pick whichever is relevant to what you're building.

You'll need:

  • A Sinch account (Project ID, Key ID, Key Secret from the dashboard)
  • For voice callouts: a Voice App with a Key and Secret
  • For messaging: a Conversation App with at least one channel configured
  • For webhook testing: a Sinch Function project running locally (see Getting Started with Sinch Functions)
  • For log streaming: a deployed Sinch Function (same Functions post)

Installing and authenticating

npm install -g @sinch/cli
Enter fullscreen mode Exit fullscreen mode

Then:

sinch auth login
Enter fullscreen mode Exit fullscreen mode

The CLI walks you through Project ID, Key ID, and Key Secret, then two follow-up questions:

? Project ID (from Sinch Dashboard): <your-project-id>
? Key ID (from Project → Access Keys): <your-key-id>
? Key Secret: **********************
✔ API credentials verified!

? Add Voice application credentials? (for voice templates and callbacks) (Y/n)
? Voice Application Key: <your-voice-app-key>
? Voice Application Secret: **********************
✔ Voice credentials verified!

? Install Sinch developer skills for AI assistants? (Claude Code, Copilot, Cursor) (Y/n)

✅ Authenticated
  Project ID: <your-project-id>
  Key ID:     <your-key-id>
  Voice App Key: <your-voice-app-key>
Enter fullscreen mode Exit fullscreen mode

Say yes to Voice Application credentials; you'll need them for callouts later. The Skills prompt only appears if Sinch Skills aren't already installed in your AI coding assistant. If you've done this before, it's skipped automatically. Either way, you don't need them for this walkthrough; more on this at the end.

If you've logged in before, the CLI detects existing credentials and offers to reuse them.

All credentials go into your OS keychain: macOS Keychain, Windows Credential Manager, or Linux Secret Service. Nothing lands in a config file in plaintext. sinch auth status will tell you which storage mode is active.

Confirm the connection:

sinch health
Enter fullscreen mode Exit fullscreen mode
✔ API is healthy

🏥 Health Status:
  Status: healthy
  API URL: https://functions.api.sinch.com
  Project ID: <your-project-id>
Enter fullscreen mode Exit fullscreen mode

Getting a number

sinch numbers available search --region US --type LOCAL --capabilities SMS VOICE
Enter fullscreen mode Exit fullscreen mode

Even with all flags passed, the CLI still asks for an optional digit pattern to filter by. This is part of the interactive mode that runs on top of the flags you've already provided. Hit Enter to skip it and get any available number. Add --non-interactive to skip all optional prompts entirely. Results show as a selectable list with capabilities and cost in your account currency:

✔ Found 20 available number(s)
? Select a number to rent (20 available):
❯ +1 202-519-9630  SMS, VOICE  0.80 EUR setup + 0.80 EUR/mo [docs required]
  +1 202-773-9769  SMS, VOICE  0.80 EUR setup + 0.80 EUR/mo [docs required]
  ...
Enter fullscreen mode Exit fullscreen mode

The [docs required] tag on some numbers means regulatory documentation is required. Check the Sinch dashboard for details on what's needed for your region.

For a specific number:

sinch numbers available check +12025550134
Enter fullscreen mode Exit fullscreen mode

To rent:

sinch numbers available rent +12025550134
Enter fullscreen mode Exit fullscreen mode

The interactive rent flow walks you through configuration for each capability the number supports:

? Configure SMS for this number? (y/N)
? Voice configuration:
❯ None (configure later)
  RTC — Real-time Communication
  EST — Elastic SIP Trunking
  FAX
? Callback URL for provisioning events (optional):
? Rent +1 202-555-0172? This will activate it on your project. (Y/n)
Enter fullscreen mode Exit fullscreen mode

If you say yes to SMS, it asks for your SMS service plan ID (find it in the Sinch SMS dashboard) and optionally a campaign ID for US 10DLC compliance. For this walkthrough, say no. You can configure it later from the dashboard. Voice lets you pick RTC, EST (which fetches your SIP trunks for selection), or Fax. Everything you'd normally do across three dashboard tabs, in one wizard. On confirmation:

✔ +1 202-555-0172 rented successfully!

  Phone Number: +1 202-555-0172
  Region:       US
  Type:         LOCAL
  Capabilities: SMS, VOICE
  Cost:         0.80 EUR/month

Manage this number: sinch numbers active get +12025550172
Enter fullscreen mode Exit fullscreen mode

After renting, confirm it's yours:

sinch numbers active list
Enter fullscreen mode Exit fullscreen mode

The command prompts for an optional region filter and number type before listing. Leave both blank to see everything:

✔ Found 3 active number(s)

+1 202-555-0172   [US] LOCAL   SMS, VOICE
+44 20-555-0134   [GB] LOCAL   VOICE
+46 70-555-0180   [SE] MOBILE  SMS
Enter fullscreen mode Exit fullscreen mode

For the full picture on a specific number, pass it in E.164 format (no spaces or dashes):

sinch numbers active get +12025550172
Enter fullscreen mode Exit fullscreen mode
✔ Number retrieved

ℹ Phone Number: +1 202-555-0172
ℹ Region:       US
ℹ Type:         LOCAL
ℹ Capabilities: SMS, VOICE
ℹ Cost:         0.80 EUR/month
ℹ Next Charge:  8/23/2026
ℹ SMS Service Plan: n/a
ℹ Voice Type:   RTC
Enter fullscreen mode Exit fullscreen mode

When you're done with it:

sinch numbers active release +12025550172
Enter fullscreen mode Exit fullscreen mode

Prompts for confirmation unless you pass --force.

Making a call

For this you need a Voice App with a Key and Secret. If you set one up during sinch auth login, you're ready. If not, run sinch auth login again and say yes when it asks for Voice Application credentials.

The examples below use separate numbers from the ones in "Getting a number". These are standalone demos, not a continuation of that workflow.

sinch voice callouts tts +46700000000 "Your shipment has been picked up."
Enter fullscreen mode Exit fullscreen mode

The CLI infers the destination type from the format: E.164 numbers route as PSTN, sip:user@host routes to SIP, a bare string routes to an in-app endpoint. You don't need to think about it for a standard phone call.

✔ TTS callout queued

ℹ Call ID:     5b5accdf-bd0d-4448-a5d3-4cca076c732b
ℹ Destination: +46700000000
ℹ Voice:       en-US

ℹ Track status with: sinch voice calls get 5b5accdf-bd0d-4448-a5d3-4cca076c732b
Enter fullscreen mode Exit fullscreen mode

A few flags worth knowing:

  • --voice en-US-Neural2-F sets a specific voice. Accepts full locale strings.
  • --cli +12039710337 sets the caller ID shown to the recipient.
  • --dtmf "1w2" sends DTMF tones after pickup; w is a 500ms pause.

Poll for the result. For a basic TTS callout with no voice function deployed, expect MANAGERHANGUP: the call connected, the recipient answered, the message played, and the platform ended the call. That's a successful delivery.

sinch voice calls get 5b5accdf-bd0d-4448-a5d3-4cca076c732b
Enter fullscreen mode Exit fullscreen mode
✔ Call info retrieved

ℹ Call ID:    5b5accdf-bd0d-4448-a5d3-4cca076c732b
ℹ Status:     FINAL
ℹ Result:     ANSWERED
ℹ Reason:     MANAGERHANGUP
ℹ Duration:   2s
ℹ Domain:     pstn
ℹ To:         +46700000000 (Number)
ℹ Timestamp:  7/23/2026, 3:45:25 PM
ℹ Rate/min:   0.323 EUR
ℹ Total cost: 0.323 EUR
Enter fullscreen mode Exit fullscreen mode

Once you have a voice function deployed to handle the ICE callback, you can keep the call alive, play a menu, collect input, and respond accordingly.

Sending a message

The examples below use separate numbers from the ones in "Getting a number". These are standalone demos, not a continuation of that workflow.

This requires a Conversation App with at least one channel configured. SMS, WhatsApp, RCS, and others are each set up separately in the Sinch dashboard. Which channels you can actually send through depends on what's configured in your app.

sinch conversation send +46700000000 "Your driver is 10 minutes away."
Enter fullscreen mode Exit fullscreen mode

If you don't specify a Conversation app with -a <app-id>, the CLI prompts you to pick one and offers to save it as the default so you're not asked again:

? Select a Conversation app:
❯ 01KTFHP5SF8SQFSNK5V7NQVKZH — My Conversation App
  Enter app ID manually
? Save as default Conversation App ID? (Y/n)
✅ Default app ID saved. You won't be asked again.
Enter fullscreen mode Exit fullscreen mode

It then asks which channel to use:

? Select channel:
❯ SMS
  WHATSAPP
  MESSENGER
  INSTAGRAM
  VIBER
  TELEGRAM
  RCS
  LINE
Enter fullscreen mode Exit fullscreen mode

Add -c SMS or -c WHATSAPP to skip the prompt and target a specific channel directly. Only channels you've configured in the Conversation App will actually work; the others will be accepted by the CLI but fail at the API level.

Output on success:

✔ Message sent successfully!

ℹ Message ID: 01KY7KS5059DMD3WDFAD3V3J8E
ℹ Recipient:  +46700000000
ℹ Channel:    SMS
ℹ Type:       text
Enter fullscreen mode Exit fullscreen mode

Testing a webhook locally

Requires a Sinch Function project on your machine (see Getting Started with Sinch Functions). Use a dedicated dev Voice App, not one handling live traffic: this rewrites its callback URL.

From your project directory:

sinch functions dev --tunnel
Enter fullscreen mode Exit fullscreen mode
🎯 Starting my-simple-voice-ivr (node)
ℹ Port: 3000

✅ ✅ Server running on http://localhost:3000

[nodemon] starting `npm run build && sinch-runtime`

Function server running on http://localhost:3000

Detected functions:
   ice (voice): POST http://localhost:3000/ice
   pie (voice): POST http://localhost:3000/pie
   dice (voice): POST http://localhost:3000/dice

Starting tunnel...
Tunnel connected successfully!
✅ Updated voice webhook URL
📱 Test Phone Numbers:
   ☎️  +12025550172
💡 Call any of these numbers to test your voice function!
Enter fullscreen mode Exit fullscreen mode

The CLI starts a local server, opens a Cloudflare tunnel, and rewrites your Voice App's callback URL to point at the tunnel. Real Sinch traffic now hits your machine. From a second terminal, call the test number shown in the startup output:

sinch voice callouts tts +12025550172 "Hello from your local function."
Enter fullscreen mode Exit fullscreen mode

The ICE callback fires against your local handler. Incoming requests and responses appear in real time in the dev server output, in the same columnar format as sinch functions logs --follow. File watching is on, so any code change restarts the server automatically.

Streaming logs

After deploying a function, sinch functions logs --follow streams live request and response data as a columnar table. Each row shows method, status code (green for 2xx, red for 4xx/5xx), duration, and URL. Expand any row to see the full request body, response body, and console.log output from inside the function.

sinch functions logs --follow
Enter fullscreen mode Exit fullscreen mode
ℹ 📋 Logs for function: my-voice-function (✅ Running)

Time        Method  Status  Duration  URL
────────────────────────────────────────────────────────────────────────────────
14:32:39  POST    200  2ms        / [ice]
  ┌ Request
  │ {
  │   "event": "ice",
  │   "callId": "8ce5c8b8-d70f-42f3-ad00-750706738f71",
  │   "cli": "46700000000",
  │   "to": { "type": "did", "endpoint": "+12025550172" },
  │   "domain": "pstn",
  │   ...
  │ }
  ├ Response
  │ {
  │   "instructions": [{ "name": "say", "text": "Press 1 for yes.", "locale": "en-US" }],
  │   "action": { "name": "runMenu", "menus": [...] }
  │ }
  └─────────────────────────────────────
Enter fullscreen mode Exit fullscreen mode

If the function has console.log calls, the output appears in a Logs section between Response and the closing separator. -i opens a full-screen TUI instead. Arrow keys navigate between requests, Enter expands the detail, Esc closes it, and Q quits.

Filter by level, text, or time window:

sinch functions logs --follow --level error
sinch functions logs --follow --search "timeout"
sinch functions logs --since 30m
Enter fullscreen mode Exit fullscreen mode

If you're not in a project directory with a sinch.json, pass the function ID directly:

sinch functions logs <function-id> --follow
Enter fullscreen mode Exit fullscreen mode

What else the CLI covers

More messaging types. sinch conversation send supports cards, carousels, choice messages, location messages, media with captions, and pre-approved templates. Card, carousel, and choice messages are built interactively by default; pass --json-message with the full message body for non-interactive use. Templates are fetched from the API and presented as a picker.

Debugging. SINCH_DEBUG=2 on any command shows request method, URL, and status code. SINCH_DEBUG=3 adds response bodies and headers. Useful when you're chasing an auth issue and want to see exactly what's being sent.

SINCH_DEBUG=2 sinch voice callouts tts +46700000000 "Test."
Enter fullscreen mode Exit fullscreen mode

Conference calls. sinch voice callouts conference <destination> <conference-id> dials a number into a conference room, created automatically if it doesn't exist.

Mid-call SVAML. sinch voice calls update <call-id> --svaml '...' injects SVAML into an active call without needing a webhook.

Fax. sinch fax send --from <number> --to <number> --file invoice.pdf

SIP trunking. sinch sip trunks covers trunks, endpoints, ACLs, and credential lists.

Number porting. sinch porting orders create starts a porting order; sinch porting documents upload handles the paperwork.

Everything accepts --json for machine-readable output and --profile <name> to switch between credential sets. With those two flags, the whole CLI is scriptable.

Troubleshooting

  • Auth errors on callouts. Voice callouts use a separate set of credentials from your Project Key/Secret: the Voice Application Key and Secret. If sinch voice callouts tts fails with an auth error, you probably skipped that step during sinch auth login. Run sinch auth login again and say yes when it asks for Voice Application credentials.
  • sinch conversation send fails after picking a channel. The CLI accepts any channel in the list, but only channels configured in your Conversation App will go through. Check your app's channel configuration in the Sinch dashboard.
  • sinch numbers active list output isn't copy-paste compatible with get. list shows numbers in formatted display format (+1 202-555-0172), but get expects E.164 (+12025550172). Strip the spaces and dashes before passing it.
  • --non-interactive hangs in CI. The CLI prompts for missing required values if you don't provide them as flags. Pass all required flags explicitly alongside --non-interactive.
  • sinch functions dev --tunnel rewrites your Voice App's callback URL. Use a dedicated dev Voice App, not one handling live traffic. If the tunnel connection fails, check whether port 3000 is already in use.
  • sinch functions logs says the function wasn't found. Log streaming requires a deployed function. If you've only run it locally with sinch functions dev, deploy it first with sinch functions deploy.

What comes next

The whole point of the CLI is that the integration workflow starts in the terminal, not in code. If you want to take that further, an AI coding assistant can drive the CLI commands for you too: describe what you need, and let it figure out which commands to run. The Sinch Skills installed during sinch auth login give Claude Code, Cursor, and Copilot knowledge of the Sinch APIs, so the same assistant writing your integration code can handle number management, callouts, and message sends alongside it. Same local-first pattern as the Functions post: real Sinch infrastructure, no context switching.

The dashboard is good for configuration you set once. The CLI is better for everything else.

Additional Resources


Curious whether you're using the CLI for anything I didn't cover here. Let me know in the comments.

Top comments (0)