# AX Check: bandwidth.com
Checked 2026-09-29.

Bandwidth's docs and pricing are clear, but llms.txt falls short
Getting-started guide and API reference give concrete steps and rates; llms.txt is a blog dump with no navigation or API/MCP links. 16 of 23 checks passed.

## Onboarding needs a login

## Coding sessions
All three independent sessions (DeepSeek V4.1 Flash, Kimi K3, Qwen 3.8 Max) completed and found pricing on bandwidth.com/pricing, producing tables of per-message and per-minute rates with stated assumptions like US list pricing excluding taxes and fees.

### DeepSeek V4.1 Flash
[View public run](https://agents.withgauge.com/p/runs/14d0beb9-01c9-4f1b-98cd-d35f6ae535f2) · [Read transcript](https://www.ax-check.com/bandwidth.com/sessions/deepseek.json)
README/final output give a pricing table (10DLC $0.004/SMS, short code $0.008, toll-free $0.007, voice rates) sourced from the fetched bandwidth.com/pricing page (seq 16-23), with named assumptions: US list pricing, usage-based, volume discounts, 10DLC registration billed separately.
#### End-to-end onboarding
- **End-to-end onboarding not demonstrated**: The agent never obtained real Bandwidth API credentials during the session. It probed the token endpoint and messaging endpoint with dummy/fabricated basic-auth values and correctly received 401 invalid_client errors, then wrote a script and README explicitly stating no Bandwidth credentials were available in the environment and that it did not send a real message. No self-service signup or credential-issuance flow was attempted or found.
  Event 86:

  ```text
  oauth token endpoint HTTP 401\nbody: {"error":"invalid_client","error_description":"Provided client credentials are invalid"
  ```
  Event 91:

  ```text
  I have no Bandwidth credentials in this environment, so I confirmed the workflow by hitting both live endpoints with dummy auth (correct 401s from the token endpoint and the messaging endpoint). I did not send a real message.
  ```
  Event 101:

  ```text
  Not blocked. The only blocker for a live send is credentials. Provide BW_ACCOUNT_ID, BW_CLIENT_ID, BW_CLIENT_SECRET, BW_APPLICATION_ID, BW_FROM, BW_TO and node send-sms.mjs will send for real.
  ```

#### Hallucinated URLs
- **Guessed messaging quickstart path returned 404**: The agent guessed a documentation URL path (dev.bandwidth.com/guides/messaging/quickstart/) that does not exist on the site, receiving a 'Page Not Found' response. This was a guess rather than a link the agent was given, and it correctly abandoned it in favor of the sitemap-derived real path (docs/messaging/quickStart), so it is a demonstrated invented URL that failed.
  Event 35:

  ```text
  Page Not Found | Bandwidth API Docs 
   Skip to main content Guides API Reference Developer Tools Samples Search Page Not Found We could not find what you were looking for.
  ```
  Event 28:

  ```text
  timeout 20 curl -sSL "https://dev.bandwidth.com/guides/messaging/quickstart/" -o /tmp/bw_msg_qs.html
  ```

#### Blockers
- **No Bandwidth credentials available to send a real message**: This is a test-environment limitation, not a product defect: the sandbox had no Bandwidth account, API credentials, phone number, or messaging application configured. The agent verified the auth and send workflow shape by hitting live endpoints with dummy credentials (getting expected 401 errors) but stopped short of an authenticated send, as instructed to do when blocked.
  Event 91:

  ```text
  I have no Bandwidth credentials in this environment, so I confirmed the workflow by hitting both live endpoints with dummy auth (correct 401s from the token endpoint and the messaging endpoint). I did not send a real message.
  ```
  Event 84:

  ```text
  messaging endpoint HTTP 401
  ```

#### Suggested Changes
- **Add OAuth 2.0 examples to the Node Messaging SDK README**: The published SDK README only shows legacy basicAuthUserName/basicAuthPassword init, but the docs site says legacy basic auth is deprecated and removed Dec 2, 2026 in favor of OAuth 2.0. Update the README 'Initialize' section to show OAuth 2.0 client-credentials setup so developers reading just the package README do not build against a soon-removed auth method. Verify by confirming the sample uses Client ID/Secret token exchange, not basicAuthUserName/basicAuthPassword.
  Event 30:

  ```text
  const client = new Client({
      basicAuthUserName: "username",
      basicAuthPassword: "password"
  });
  ```
  Event 66:

  ```text
  Bandwidth's legacy API User (username/password) authentication method is deprecated and will be removed December 2, 2026. OAuth 2.0 Client Credentials will be the only supported authentication method going forward.
  ```
- **Fix the broken /guides/messaging/quickstart/ style link**: A plausible, conventionally-formed docs URL path for the messaging quickstart returned a 404, while the real page lives at a differently-structured path only discoverable via the sitemap. Add a redirect from guessed paths like /guides/messaging/quickstart/ to the canonical /docs/messaging/quickStart page, and confirm by requesting the old-style URL and checking it 200s or redirects instead of 404ing.
  Event 35:

  ```text
  Page Not Found | Bandwidth API Docs 
   Skip to main content Guides API Reference Developer Tools Samples Search Page Not Found We could not find what you were looking for.
  ```
  Event 54:

  ```text
  docs/messaging/quickStart -> 37836
  ```

### Kimi K3
[View public run](https://agents.withgauge.com/p/runs/5fbf2ea9-16f6-439e-bdd2-0f8bb70d5b82) · [Read transcript](https://www.ax-check.com/bandwidth.com/sessions/kimi.json)
Final output gives a pricing table sourced from bandwidth.com/pricing (seq 12,15) with explicit assumptions stated: 'US, pay-as-you-go', per-number-type SMS/MMS rates, per-minute voice rates, and notes on volume discounts.
#### End-to-end onboarding
- **Onboarding needs a login**: The agent never obtained real Bandwidth credentials. It wrote two scripts (send-sms.js, check-account.js) that require env vars like BW_ACCOUNT_ID, BW_USERNAME/PASSWORD, and BW_VOICE_USERNAME/PASSWORD, but no signup or credential-issuance flow was run. Both scripts were executed and immediately exited with 'Missing env vars' errors because no credentials existed. The agent explicitly states it has no Bandwidth credentials and that Bandwidth requires manual trial signup with business email approval, which it could not complete in this session.
  Event 39:

  ```text
  Missing env vars: BW_ACCOUNT_ID, BW_MESSAGING_APPLICATION_ID, BW_USERNAME, BW_PASSWORD, BW_FROM_NUMBER, TO_NUMBER
  exit=1
  Missing: BW_ACCOUNT_ID, BW_VOICE_USERNAME, BW_VOICE_PASSWORD
  exit=1
  
  ```
  Event 44:

  ```text
  I have **no Bandwidth credentials** in this environment, so I can't execute a live send. Bandwidth has no instant self-serve API key — you sign up for a **free trial** (business email + approval), get an account ID, generate API tokens/secrets per product, and create a Messaging "Application" in the dashboard.
  ```

#### Hallucinated URLs
None identified in this transcript.

#### Blockers
- **No self-serve API credentials available**: Bandwidth requires signing up for a free trial via business email and manual approval before any API key or account ID is issued. The agent had no such credentials in the sandbox and could not obtain them programmatically, so it could not execute a live SMS send or authenticated Voice API call. This is a missing-credentials limitation rather than a product code defect — the SDK itself instantiated correctly and the API endpoints responded (401/403, confirming they are live).
  Event 44:

  ```text
  Bandwidth has no instant self-serve API key — you sign up for a **free trial** (business email + approval), get an account ID, generate API tokens/secrets per product, and create a Messaging "Application" in the dashboard. Trial accounts can only message verified numbers until activated.
  ```
  Event 24:

  ```text
  messaging api unauth: 401
  voice api unauth: 403
  
  ```

#### Suggested Changes
None identified in this transcript.

### Qwen 3.8 Max
[View public run](https://agents.withgauge.com/p/runs/98396024-3fb7-4795-a356-ed10729fa2fe) · [Read transcript](https://www.ax-check.com/bandwidth.com/sessions/qwen.json)
README.md pricing section gives per-message/per-minute rates and explicitly names assumptions: 'published US list rates... excludes taxes and regulatory recovery fees', notes numbers fees are dashboard/quote-only, and no free tier/sandbox.
#### End-to-end onboarding
- **Onboarding needs a login**: The agent never obtained real Bandwidth credentials. It self-generated placeholder values (fake account id, fake username/password) in a local .env file purely to exercise error handling, then hit 401 Unauthorized on every live call against both the Numbers API and Messaging API. No sign-up flow, API key retrieval, or OAuth token acquisition occurred; the agent explicitly states it cannot self-provision an account.
  Event 323:

  ```text
  BANDWIDTH_ACCOUNT_ID=1234567
  BANDWIDTH_USERNAME=fake_user
  BANDWIDTH_PASSWORD=fake_pass
  ```
  Event 328:

  ```text
  Numbers API FAILED -> 401 Unauthorized - Bandwidth rejected the credentials (check username/password or client id/secret).
  ```
  Event 355:

  ```text
  there are no Bandwidth credentials or account id here, and
    Bandwidth has no anonymous sandbox
  ```

#### Hallucinated URLs
- **Guessed numbers pricing doc path**: The agent constructed a plausible-looking docs URL for numbers pricing that does not exist on the Bandwidth docs site, returning a 404 with a generic 'Page Not Found' template (distinct from a broken external link scenario since the agent built this URL from a naming pattern rather than following a discovered link).
  Event 33:

  ```text
  == https://dev.bandwidth.com/docs/numbers/pricing
  404
  Page Not Found | Bandwidth API Docs
  ```
- **Guessed numbers getting-started guide path**: The agent guessed a getting-started guide URL under the numbers docs path following a common pattern (guides/getting-started); the request returned a 404 with no content, indicating the path was invented rather than sourced from a link on the site.
  Event 133:

  ```text
  404
  6
  
  ```
  Event 132:

  ```text
  https://dev.bandwidth.com/docs/numbers/guides/getting-started/
  ```

#### Blockers
- **No Bandwidth account credentials available in the sandbox**: This is a test-environment limitation, not a product defect: the sandbox has no Bandwidth account, API username/password, or OAuth client credentials, and Bandwidth offers no free/anonymous sandbox tier. Every live call the agent made against the Numbers API and Messaging API returned 401 Unauthorized once real credentials were required.
  Event 328:

  ```text
  Numbers API FAILED -> 401 Unauthorized - Bandwidth rejected the credentials (check username/password or client id/secret).
  ```
  Event 355:

  ```text
  there is
  no free tier and no published sandbox credit — you need a real account (trial or paid) to
  call the APIs at all.
  ```
- **Legacy Numbers SDK has undocumented, inconsistent return shapes**: Agent error while integrating the bandwidth-numbers-sdk: calling .list() on Sites returned either a raw list or a wrapper object depending on call site, causing an AttributeError before the agent wrote a normalizing helper (as_items). This is friction from the SDK's inconsistent API surface (legacy XML-based client), which the agent worked around in code rather than being a hard product blocker.
  Event 192:

  ```text
  AttributeError 'Client' object has no attribute 'client'
  ```
  Event 200:

  ```text
  HTTPError 401 Client Error:  for url: https://dashboard.bandwidth.com/api/sites
  ```
- **Messaging SDK ApiClient lacks documented .close() method**: Agent error/SDK friction: the generated bandwidth-sdk ApiClient does not expose a .close() method as the README's getting-started example implies via context manager usage; calling it directly raised AttributeError, requiring a workaround helper function.
  Event 328:

  ```text
  Messaging API FAILED -> AttributeError: 'ApiClient' object has no attribute 'close'
  ```

#### Suggested Changes
- **Fix broken links to numbers pricing and numbers getting-started pages**: Both https://dev.bandwidth.com/docs/numbers/pricing and https://dev.bandwidth.com/docs/numbers/guides/getting-started/ return 404s on the dev docs site. Verify whether canonical numbers pricing/getting-started content exists elsewhere (e.g. under /apis/numbers-apis/) and add redirects or fix internal links pointing to these paths; check by curling the URLs and confirming a 200 with relevant content.
  Event 33:

  ```text
  == https://dev.bandwidth.com/docs/numbers/pricing
  404
  Page Not Found | Bandwidth API Docs
  ```
  Event 133:

  ```text
  404
  6
  
  ```
- **Add a migration note or update README for the legacy Python Numbers SDK**: The bandwidth-numbers-sdk README's usage examples don't disclose that .list() calls can return a wrapper object with .items rather than a plain list depending on model type, which caused an AttributeError during integration. Add a short compatibility note or type hint table in the SDK README (github.com/Bandwidth/python-numbers-sdk) clarifying return types for list()/get() across resource classes; confirm by having a new integrator use Sites.list() and SipPeers.list() without hitting attribute errors.
  Event 192:

  ```text
  AttributeError 'Client' object has no attribute 'client'
  ```
  Event 110:

  ```text
  []
  ['Client']
  ```
- **Publish per-number monthly recurring fee and order fee on the public pricing page**: The public pricing page (bandwidth.com/pricing) lists usage rates for messaging/voice/auth but omits per-number order and monthly recurring fees, forcing the agent to note these are dashboard/quote-only. Add a numbers section to the pricing page with these fees; verify by checking the rendered pricing page includes a 'Phone Numbers' pricing row.
  Event 29:

  ```text
  Messaging
  Voice
  Authentication
  SIP Trunking
  Number type
  SMS outbound
  MMS outbound
  ```

### Task given to each agent
Help me build a simple example using Bandwidth. Tell me how pricing works, and briefly tell me whether this product will be easy for you to manage. Let me know if you get blocked. If this product has no developer workflow you can act on, say so plainly and stop. Stay light: use the hosted product through its SDK or API. Do not start local service stacks or wait for long-running commands; if the quickstart requires either, say so plainly and stop.

No product credentials were supplied and no purchases were authorized.

## Score: B · 73/100 (provisional)
Grades come from completed site checks. Coding sessions and skipped checks do not affect the score.

### Clarity
- **Failed** — llms.txt provides an actionable documentation index

  ```text
  llms.txt exists but is a huge blog/customer dump, not an actionable docs index.
  ```

- **Failed** — llms.txt provides navigation guidance

  ```text
  llms.txt offers no navigation guidance or starting path for agents.
  ```

- **Failed** — llms.txt mentions offered API, MCP, and skills

  ```text
  llms.txt links no API reference, MCP server, or skills despite offering APIs.
  ```

- **Pass** — Homepage answers Markdown requests

  ```text
  Homepage returned text/markdown (200) when requested with Accept: text/markdown.
  ```

- **Pass** — A compact guide representation exists

  ```text
  Bandwidth publishes a standalone Markdown getting-started guide at dev.bandwidth.com/docs/universal-platform/getting-started.md.
  ```

- **Pass** — A focused guide is directly retrievable

  ```text
  The .md guide is directly retrievable with concrete steps: restrictions, purchase, activation, service order.
  ```

- **Pass** — Equivalent instructions fit a token budget

  ```text
  Markdown guide measures 3696 tokens, well under the 8000-token budget.
  ```

- **Pass** — Product-docs links survive format changes

  ```text
  Markdown guide preserves docs links (order-numbers, create-a-rp, create-a-vcp, quickStart) as .md routes.
  ```

- **Pass** — The compact guide is independently actionable

  ```text
  Universal Platform quickstart gives concrete steps: retrieve restrictions, order number, activate services with API calls.
  ```

- **Pass** — Install and next-step links resolve

  ```text
  Getting-started, API reference and samples links fetched successfully; one .md link 404s but HTML route works.
  ```


### Onboarding
- **Pass** — Docs lead to a relevant quickstart

  ```text
  Docs Getting Started page walks through purchasing, configuring and provisioning a global number with concrete steps.
  ```

- **Pass** — Installation commands are extractable

  ```text
  Getting Started shows extractable HTTP request commands with Authorization bearer token headers.
  ```

- **Pass** — Code examples are available without interaction

  ```text
  Getting Started page includes full request and response code examples without interaction.
  ```

- **Pass** — Prerequisites and auth boundaries are explicit

  ```text
  Guide lists prerequisites (contracted UP account, services enabled) and Bearer token auth in examples.
  ```


### Pricing
- **Pass** — Pricing is readable without interaction

  ```text
  Bandwidth pricing page renders rates directly in fetched Markdown, no interaction needed.
  ```

- **Pass** — Prices are stated, not gated

  ```text
  Concrete rates stated: SMS $0.004/message, voice $0.0055/min, transcription $0.0450/min.
  ```

- **Pass** — Pricing units and limits are explicit

  ```text
  Units explicit per message, per minute, per 100 char, per call, per auth.
  ```

- **Pass** — Agents identify pricing and its assumptions

  ```text
  3 of 3 sessions were judged on pricing; 0 fell short. DeepSeek V4.1 Flash: README/final output give a pricing table (10DLC $0.004/SMS, short code $0.008, toll-free $0.007, voice rates) sourced from the fetched bandwidth.com/pricing page (seq 16-23), with named assumptions: US list pricing, usage-based, volume discounts, 10DLC registration billed separately. Kimi K3: Final output gives a pricing table sourced from bandwidth.com/pricing (seq 12,15) with explicit assumptions stated: 'US, pay-as-you-go', per-number-type SMS/MMS rates, per-minute voice rates, and notes on volume discounts. Qwen 3.8 Max: README.md pricing section gives per-message/per-minute rates and explicitly names assumptions: 'published US list rates... excludes taxes and regulatory recovery fees', notes numbers fees are dashboard/quote-only, and no free tier/sandbox. This behavioural item does not affect the fast grade.
  ```


### Activation
- **Failed** — An MCP server is documented and well-formed

  ```text
  Glossary says Bandwidth's locally hosted MCP server exists, but no install/config or tool list is documented.
  ```

- **Pass** — An API reference or OpenAPI spec is reachable

  ```text
  Bandwidth API Reference index lists Numbers, Messaging, Voice, RTC, Insights, Universal Platform, Emergency, MFA APIs.
  ```

- **Skipped** — A CLI install path is documented

  ```text
  No Bandwidth CLI install path appears in the fetched docs, tools or getting-started pages.
  ```

- **Skipped** — SDK packages resolve on their registries

  ```text
  No Bandwidth SDK or package registry lookup result was supplied in the fetched evidence.
  ```

- **Skipped** — Agent skills are published

  ```text
  No agent skills surface for Bandwidth appears in any fetched document.
  ```



[Full report data](https://www.ax-check.com/bandwidth.com/report.json)
