# NovoDID public API

**NovoDID public API · contract 1.5.0.** English (US) is the primary edition; Portuguese (Brazil) and Spanish (Colombia) cover the same contract. Language editions do not change API behavior or translate response keys, scope names, enums, or errors (messages may be in Portuguese).

## What you can do
List your active phone numbers (DIDs), inspect forwarding, configure telephone/SIP/public-IP forwarding, create or reuse a SIP extension while configuring forwarding, securely retrieve its credentials, list incoming calls, and read/send eligible SMS. Number release, subscription changes, API token creation and webhook administration are available through the dashboard. Token and webhook management is available in the authenticated dashboard.

## Quick start
1. In the NovoDID dashboard, open **Desenvolvedores → Tokens**. Create a token with only the required permissions and number selection. API access is automatic for individual and business accounts; administrative blocks still apply.
2. Copy the token when created (it is shown once). Store it as a local/private Postman environment value named **novodid_token**. Never save a real token in shared collection values, examples, exports, or source control.
3. Set **baseUrl** to your intended environment; the default is https://novodid.com. First run **GET /me**, then **GET /dids** with dids:read. Copy an authorized numeric id into **didId**; a phone number is not an id.
4. Optional filters are disabled by default. Enable only the filters you need. Set destination variables yourself before using writes. Inspect each response example before executing a request.
5. Run write requests individually and intentionally: they change live forwarding or send an actual SMS. This collection is documentation, not a sandbox, and must not be run wholesale against production. Saved examples are fictitious, not real customer data.

## Authentication and number access
Every request inherits Authorization: Bearer {{novodid_token}}. HTTPS is required. No wildcard scope exists. Tokens can cover all current/future numbers or 1–100 selected current number assignments. Access also requires current active ownership; an old assignment never grants access to a former customer's SMS/calls. Reacquiring a number does not reactivate an old selected assignment: issue a new token selection. Expired, revoked, blocked, and out-of-scope access is denied.

Token names: 3–80 characters; maximum 10 active unexpired tokens. Available lifetimes: 7, 30, 90, 365 days or no expiry; the dashboard suggests 90 days. Rotation invalidates the old token immediately while preserving permissions, number restrictions, expiration and quota consumption. Legacy tokens may retain broader account-wide permissions; review and replace them with narrowly scoped tokens. Revoking an API token does not revoke SIP credentials already retrieved.

## Permissions
| Scope | Capability |
|---|---|
| dids:read | List/detail active authorized numbers |
| account:read | Include account name/email in /me |
| billing:read | Include cycle, expiry, renewal and payment fields in DID responses; also needs dids:read to call those endpoints |
| forwarding:read | Read forwarding destinations, including embedded DID response fields |
| forwarding:write | Configure existing SIP or public-IP forwarding |
| forwarding:phone | Configure telephone forwarding (Siga-me) |
| forwarding:delete | Remove forwarding |
| calls:read | Read incoming call records |
| sms:read | Read eligible SMS history |
| sms:send | Send/reply to eligible SMS |
| sip:create | Create/reuse own extension as part of SIP forwarding; also requires forwarding:write and sip:credentials:read |
| sip:credentials:read | Retrieve own exclusive extension credentials |

## Limits and errors
Default aggregate limits per account, shared by every token: reads 60/min, forwarding writes 10/min, SMS 5/min and 100/day (UTC). Optional stricter token limits are additional, never additive capacity. Creating/rotating tokens does not reset usage. Rejected attempts can consume quota. Inspect X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and Retry-After; SMS also exposes X-RateLimit-Sms-Day-* headers. On 429, wait as instructed and use bounded backoff with jitter.

JSON bodies: at most 16 KiB and 16 top-level fields. Query strings: at most 2048 characters; unknown or duplicate parameters are rejected. Numeric ids: integers 1–2147483647, no decimals or exponent notation. Responses containing customer data use Cache-Control: no-store.

Errors use {"error":{"code":"...","message":"...","details":{}}}; details is optional. 400 = invalid input; 401 = missing/invalid/expired token; 403 = missing scope, account block or SMS policy; 404 = resource unavailable to this token/current ownership; 408 = body timeout; 409 = incompatible state or insufficient balance; 413 = body too large; 429 = quota; 502/503 = temporary service failure. Fix validation/authentication errors before retrying. A 404 is not proof that a number does not exist globally. Do not blindly retry SMS after a timeout: submission may already have happened and no idempotency-key contract exists.

## Response conventions
DID type values remain fixo, movel or unknown. Payment method is pix, card or null. Without billing:read, cycle/expiresAt/autoRenew/payment are null; without forwarding:read, forwarding details are hidden. Null means unavailable or not permitted, not necessarily disabled. SMS capability is independent of token permission: landline numbers do not support SMS and mobile eligibility must still be satisfied. Timestamps use the returned ISO date/time and timezone; do not assume your local timezone.

## Integration recipes
**Read-only dashboard:** dids:read, optionally billing:read and forwarding:read; poll within shared limits. **SMS inbox/reply:** sms:read + sms:send; reply with from=your DID and to=the inbound sender. **Softphone setup:** forwarding:write + sip:create + sip:credentials:read; PATCH type=sip without sipAccountId, then configure the returned server/username/password/port/transport. Add forwarding:read to inspect the destination. **Telephone forwarding:** forwarding:phone and sufficient account balance; charge is BRL 0.20/min from the first billable minute, with no free allowance.

## Webhooks (dashboard configuration)
Open Desenvolvedores → Webhooks, add a name (3–80 characters), public HTTPS URL (up to 2048 characters), events and optionally up to 50 owned DIDs. An empty DID filter means all eligible numbers. URLs with credentials, private/local hosts or redirects are not accepted. Available events: sms.received, sms.sent, call.received, call.missed, payment.approved, did.expiring. There are no public v1 webhook CRUD endpoints in this collection; webhook settings are separate from API token scopes.

The envelope contains id, type, version, createdAt and data; event-specific data can include did, sms, call or payment. Dashboard tests have data.test=true. Preserve the exact raw request body to verify X-Novodid-Signature: sha256= + HMAC-SHA256(secret, X-Novodid-Timestamp + "." + rawBody). Compare in constant time, reject stale timestamps (recommended ±5 minutes) and deduplicate by event id. X-Novodid-Event and X-Novodid-Delivery also identify delivery context. 

Persist/enqueue the validated event and promptly return 2xx. Delivery has an 8-second total deadline, no redirects, limited response capture, and up to five attempts with backoff. Repeated failures can pause an endpoint. Monitor dashboard delivery logs and fix reachability, TLS, signature/body parsing, and response time before resuming. Do not assume ordering, exactly-once delivery, or historical replay. Ownership is rechecked before delivery; releasing a DID does not transfer its history to a new customer.

## References
[Dashboard](https://novodid.com/desenvolvedores) · [OpenAPI](https://novodid.com/developers/novodid-api-v1.openapi.json) · [Detailed guide](https://novodid.com/developers/novodid-api-v1.md).

## Code examples

Read-only examples. Set NOVODID_API_TOKEN in your local environment; never hardcode it. 

### cURL

```bash
curl --fail-with-body --max-time 15 \
  https://novodid.com/api/v1/dids \
  -H "Authorization: Bearer $NOVODID_API_TOKEN" \
  -H "Accept: application/json"
```

### Node.js (fetch)

```javascript
const token = process.env.NOVODID_API_TOKEN;
if (!token) throw new Error("NOVODID_API_TOKEN is required");
const response = await fetch("https://novodid.com/api/v1/dids", {
  headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
  signal: AbortSignal.timeout(15000),
  redirect: "error"
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const { dids } = await response.json();
console.log({ count: dids.length });
```

### Python (requests)

```python
import os
import requests

response = requests.get(
    "https://novodid.com/api/v1/dids",
    headers={"Authorization": "Bearer " + os.environ["NOVODID_API_TOKEN"]},
    timeout=15,
    allow_redirects=False,
)
if response.status_code != 200:
    raise RuntimeError(f"HTTP {response.status_code}")
dids = response.json()["dids"]
print({"count": len(dids)})
```

## Interactive reference

The [NovoDID reference](https://novodid.com/desenvolvedores/referencia) provides the same endpoint coverage, separate forwarding variants, cumulative scopes and code examples in eight languages. HTTP 500 indicates an internal error.

## DID purchases and MCP

Use catalog:read to search numbers for sale and quote a subscription, orders:create to create a payment checkout, and orders:read to retrieve/list your account's orders. Existing tokens do not receive these permissions automatically. Purchasing requires an unrestricted number selection on the token, an active eligible account, completed required verification, available account capacity and the same mobile/cycle/SMS rules used by the dashboard.

Each order contains exactly one DID. quantity may be omitted or set to the integer 1; arrays and bulk quantities are rejected. A pending reservation applies only to the selected DID and lasts at most 15 minutes from order creation. Other DIDs may be purchased during this period, subject to account limits. Monthly, semiannual and annual cycles are supported. Prices are calculated on the server in BRL cents. Catalog prices are monthly references; quote returns the full cycle price, discounts and card fee. A quote does not reserve stock.

Show the number, cycle, recurring amount and SMS conditions to the customer. Only after their consent, send the required boolean acknowledgement: fixedDidSmsAcknowledged=true for landlines; mobileMonthlySmsAcknowledged=true when the quote requires it. Agents must not assume consent.

POST /api/v1/orders requires an Idempotency-Key header containing 16–128 letters, digits, hyphens or underscores. Generate a new key for a new purchase intent; reuse the same key and body after a timeout. Changing the body with the same key returns 409 idempotency_conflict. Never generate a fresh key just to retry an uncertain payment. Error details may include orderId for follow-up.

Pix uses a recurring authorization and returns pix.copyPaste and pix.qrCodeDataUrl. Open your banking app and review the payment and recurring authorization. Card checkout returns checkoutUrl, which the customer opens to enter and confirm payment details. Creating an order does not pay for or activate a DID. A browser return is not payment confirmation.

Order states: creating, awaiting_payment, paid (activation pending), active (activation completed), expired, cancelled, refunded, rejected and review_required. Get the order to track progress; GET /api/v1/dids confirms current active ownership. Payment instructions are returned only while awaiting_payment. A pending reservation expires within 15 minutes, including failed creation or orders requiring review. This does not confirm immediate external cancellation or a refund. Do not pay expired instructions; a payment confirmed after expiry is reviewed without replacing another reservation or ownership. Already confirmed payments and active numbers remain protected. For review_required, contact support with the order ID.

Remote MCP: https://mcp.novodid.com/mcp, Streamable HTTP, authenticated with the same NovoDID Bearer API token. Tools: search_available_dids, quote_did_purchase, create_did_checkout, get_did_order, list_did_orders. Only permitted tools are listed. create_did_checkout receives idempotencyKey as an argument. Pix results include copy/paste text, a PNG QR image and terminalQr text; render the terminal representation with a monospaced font. If your client cannot show images, use the exact copy/paste text. A client must support configuring a Bearer token for this connection.


## MCP tools for your account

The remote MCP supports all public API operations through 19 tools, including the five purchasing tools. Connect to https://mcp.novodid.com/mcp using Streamable HTTP and the same Bearer token. Tool discovery respects scopes; execution preserves current ownership, token DID restrictions, quotas and field permissions. billing:read reveals payment and expiry; account:read reveals name/email; forwarding:read reveals destinations. SIP creation requires all three listed scopes. Phone forwarding requires credit and costs BRL 0.20/minute with no free allowance. SMS sending is not idempotent: do not automatically retry uncertain results. Confirm writes with the customer. OAuth is not supported by this connection. Guide: https://novodid.com/desenvolvedores/mcp

| Tool | Required scopes | Public API operation |
|---|---|---|
| `get_account` | No additional scope | `GET /api/v1/me` |
| `list_dids` | dids:read | `GET /api/v1/dids` |
| `get_did` | dids:read | `GET /api/v1/dids/{didId}` |
| `list_forwardings` | forwarding:read | `GET /api/v1/forwardings` |
| `get_did_forwarding` | forwarding:read | `GET /api/v1/dids/{didId}/forwarding` |
| `set_did_phone_forwarding` | forwarding:phone | `PATCH /api/v1/dids/{didId}/forwarding` |
| `set_did_ip_forwarding` | forwarding:write | `PATCH /api/v1/dids/{didId}/forwarding` |
| `set_did_sip_forwarding` | forwarding:write | `PATCH /api/v1/dids/{didId}/forwarding` |
| `create_did_sip_forwarding` | forwarding:write + sip:create + sip:credentials:read | `PATCH /api/v1/dids/{didId}/forwarding` |
| `delete_did_forwarding` | forwarding:delete | `DELETE /api/v1/dids/{didId}/forwarding` |
| `get_did_sip_credentials` | sip:credentials:read | `GET /api/v1/dids/{didId}/sip-credentials` |
| `list_calls` | calls:read | `GET /api/v1/calls` |
| `list_sms_messages` | sms:read | `GET /api/v1/sms/messages` |
| `send_sms` | sms:send | `POST /api/v1/sms/messages` |


During temporary mobile-number offers, available billing cycles and SMS inclusion may vary. Always request a quote: did.smsEnabled states whether SMS is included, and acknowledgements.mobileMonthlySms.required indicates whether mobileMonthlySmsAcknowledged=true is required after customer consent. Despite their names, these fields apply to any mobile cycle without SMS. A quote does not guarantee an offer; conditions are checked again when payment is created. Payments issued during an offer keep their conditions until the payment itself expires. After an offer ends, new purchases follow current conditions, while completed subscriptions keep their cycle and SMS entitlement on renewals for as long as the subscription remains in effect. This is not a price guarantee. Account eligibility, verification, limits, available stock and one number per order remain required.


409 checkout_initializing means another purchase for this account is still being prepared. Wait briefly and retry with the same Idempotency-Key and request body. This wait applies only to initial creation, not to the 15-minute payment period.

409 order_expired means the checkout creation response arrived after the order deadline. No expired QR code or checkout link is returned. Check details.orderId before starting another purchase, and do not pay old instructions.


## Account security review

While an account is under security review, reads and operations are blocked with HTTP 403 and code account_security_review, including previously issued tokens. Do not bypass the restriction or retry automatically. Access resumes after administrative release; other limits and restrictions still apply. Pending webhooks and events during the restriction are suppressed without automatic replay. Billing, due dates and expiration follow existing rules. Follow the review at https://novodid.com/seguranca/atendimento. Only the linked security ticket can be read and answered, including attachments, on the authenticated website. Other tickets and the public API remain blocked. The customer must wait for the first staff message and may send only one reply to each new staff message, including requested attachments.

Telephone confirmation and current ownership are also required for forwarding, SIP credentials, calls and SMS. Read unavailability does not change the billing contract.

Public documentation: https://docs.novodid.com/
MCP: https://docs.novodid.com/mcp/
