{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"67f16f46-0fc7-44a3-a30c-4cf687f69c5c","name":"NextAgency API v2","description":"## Introduction\n\nOur APIs make it easy to customize NextAgency for your company. From creating new leads to\ncustom apps for backend data, we'll walk you through the tools you need to build new\nintegrations and extend the power of NextAgency.\n\nThe API is REST over HTTPS. Every response is JSON, encoded UTF-8. All endpoints live under\n`/api/v2` and are authenticated with an OAuth 2.0 bearer token. Before you write any code,\nread **Enabling the API**, **Data visibility**, and **Errors**: together they explain what your\ntoken can reach and what the API does when a request is not accepted.\n\nIf you have any questions, reach out to us at support@nextagency.com.\n\n---\n\n## Base URL\n\nYour agency has its own NextAgency host. It is the domain you sign in to, and it is the base\nfor every API call:\n\n```\nhttps://{your-agency}.nextbroker.io/api/v2/...\n```\n\nSet the `domain` variable at the top of this collection to your own host before running any\nrequest. The examples on this page use a demonstration agency, so copying a URL verbatim will\nnot reach your data.\n\n---\n\n## Enabling the API\n\n**Before you begin.** The NextAgency API is an add-on. An administrator at your agency enables\nit under **Settings → Integrations → API**. Once it is on, that page holds the credentials you\nneed:\n\n- **Client ID** and **Secret ID** for your agency's OAuth application.\n- **Scopes** granted to the application.\n- **Redirect URLs.** You can register more than one, so several integrations can share the\n  single application without overwriting each other's callback.\n\nEach agency has one API application. API usage is metered and shown on your billing page.\n\n> **If the add-on is not enabled, requests return `200` — not a 4xx.** The body carries an\n> `error` key instead of a `data` key:\n>\n> ```json\n> { \"error\": \"You haven't subscribed for {Your Agency} API Application. To get access for API kindly visit you NextAgency portal.\" }\n> ```\n>\n> An unpaid balance for the previous month's requests returns `200` with an `error` the same\n> way. **Check for the presence of a `data` key** rather than relying on the status code.\n\n---\n\n## Authentication\n\nThe API uses the OAuth 2.0 authorization code flow. Redirect the user to `/oauth/authorize`\nto obtain a `code`, then exchange it for a token at `/oauth/token`, and send the token on\nevery request as `Authorization: Bearer {access_token}`.\n\n**Grant types.** The API supports `authorization_code` and `refresh_token`. Other grant types\nare not supported for reaching `/api/v2`.\n\n**Token lifetime.** An access token is valid for **24 hours**. Exchange your refresh token at\n`/oauth/token` before it expires to get a new pair. A refresh issues a new access token and\nrotates the refresh token. An access token issued before a refresh remains valid until its own\nexpiry, so treat a refresh as additive rather than as an immediate revocation of the old token.\n\n**Scopes.** Tokens are issued with the scopes configured on your agency's API application,\nnormally `read write`.\n\n---\n\n## Data visibility\n\nA token acts as the user who authorized it. Read endpoints return only the records that user\ncan see in the NextAgency web application, based on their role and on the cases assigned to\nthem. An administrator's token sees the full agency; a broker's token sees their own book.\n\nTwo consequences worth planning for:\n\n- A user with no assigned cases receives an empty `data` array, not an error.\n- Requesting a record the user cannot access returns `404 Not Found` rather than a partial\n  result.\n\nIf your integration needs agency-wide visibility, authorize it as a user who has agency-wide\nvisibility in the web application.\n\n---\n\n## Response format\n\nSuccessful responses wrap their payload in a **`data`** key:\n\n```json\n{ \"data\": { \"id\": \"...\", \"name\": \"...\" } }\n```\n\nError responses replace `data` with an **`error`** key. See **Errors**.\n\n> **One exception.** The `schema/{resource}/field_values` endpoints return their payload at the\n> top level, with no `data` wrapper. See the Schema folder.\n\n---\n\n## Pagination\n\nList endpoints page with `limit` and `offset`.\n\n| Parameter | Default | Maximum | Notes |\n| --- | --- | --- | --- |\n| `limit` | 10 | 50 | Values above 50 are capped at 50 rather than rejected. |\n| `offset` | 0 | — | An offset past the end returns an empty `data` array. |\n\nRequest pages until a response returns fewer rows than the limit you asked for.\n\n**Commission import errors page differently.** `GET /commission_imports/:id/errors` uses `page`\nand `per_page`, and returns `total`, `total_pages` and `per_page` in the body. It is the one\nendpoint that does not use `limit` and `offset`.\n\n---\n\n## Errors\n\nErrors return the appropriate HTTP status with a JSON body describing the problem.\n\n| Status | Meaning | What to do |\n| --- | --- | --- |\n| `401` | Missing, malformed, or expired bearer token. | Refresh the token and retry once. |\n| `403` | Token is valid but lacks the scope for this operation. | Check the scopes on your API application. |\n| `404` | No such record, or the authorizing user cannot see it. | See **Data visibility**. Do not assume the record is deleted. |\n| `422` | The request was understood but failed validation. | Read the message; correct the payload. Do not retry unchanged. |\n\n**404 response**\n\n```json\n{\n  \"error\": \"Resource not found.\"\n}\n```\n\n**422 response**\n\n```json\n{\n  \"error\": \"Assigned to does not match any user in this account.\"\n}\n```\n\nEvery response carries an **`x-request-id`** header. Quote it when contacting support about a\nspecific call.\n\n> **Two different `error(s)` shapes.** Validation and auth failures use a single `error` **string** (below). Separately, `GET /commission_imports/:id/errors` returns an `errors` **array** — that is a domain payload listing row-level import problems, not a validation envelope. Do not parse one as the other.\n\n> `error` is a **string**, not an object. Validation failures are joined into one sentence\n> (for example `\"First name can't be blank and Name can't be blank\"`). There is no field-keyed\n> error map, so parse it for display rather than for control flow.\n\n### Known inconsistencies\n\n- **422 comes only from the paths that validate.** Not every write validates. Several `POST`s accept an empty or invalid body with a `200` and silently create or default (benefits, notes, contacts, sub-agents), so treat a `422` as one possible outcome of a write, not a guaranteed one.\n- **Contacts create and update do not validate input.** `POST` (Create Contact) and `PATCH` (Update Contact) accept any payload with a `200`; invalid or malformed values are stored exactly as sent, and no `422` is ever returned. Validate Contact fields client-side before sending.\n- **Unknown fields are ignored, not rejected.** Sending a field this API does not recognise returns `200` and silently discards it. Verify a write took effect by reading the record back.\n- **Some invalid enum values fall back to a default** rather than returning `422`. See\n  `market_segment` on Create Case.\n- **Endpoints with no delete return `500`, not `405`.** Only notes can be deleted. That `500`\n  is the permanent answer, not a transient failure — do not retry it.\n\n---\n\n## Usage and limits\n\n**50 requests per minute**, measured per **client IP address**.\n\n- The limit is keyed on IP, **not** on access token, application, or agency. Multiple\n  integrations behind one outbound IP share a single budget, so **you may hit `429` well\n  below 50 of your own requests** if other traffic shares your egress address.\n- Exceeding it returns `429` with:\n  ```json\n  { \"error\": \"Rate limit exceeded. Please Try again after 1 minute.\" }\n  ```\n- **No `Retry-After` header and no `RateLimit-*` headers are sent.** Implement your own pacing:\n  keep sustained throughput under 50 requests per minute, and retry a `429` after a fixed delay\n  of at least 60 seconds.\n- The window is a fixed 60-second bucket, so a burst can trip the limit well inside a minute.\n\nYour own consumption is reported on your billing page as **Total API requests received**.\n\n---\n\n## Versioning\n\nThe current API is **v2**, reached at `/api/v2`. The version is part of the path, so a future\nversion will not change the behaviour of an existing integration.\n\nWithin v2 we treat these as **non-breaking** and may ship them at any time: adding an endpoint,\nadding a field to a response, adding an optional request parameter. Write your client so that\nunfamiliar fields are ignored rather than treated as errors.\n\nWe treat these as **breaking**: removing or renaming a field, changing a field's type, changing\na status code, or narrowing what a token can read. Breaking changes are recorded in the\nchangelog below.\n\n---\n\n## Changelog\n\n| Date | Change |\n| --- | --- |\n| 5 Aug 2026 | `assigned_to` on tasks and notes now accepts and persists more than one user. |\n| 22 Jul 2026 | Corrected the validation message returned when an assignee is not associated with the case. |\n| 15 Jul 2026 | Added field value enumeration for benefits, tasks, and employees. |\n| 2 Jul 2026 | **Breaking.** Validation failures now return `422`. They previously returned `200` with an error in the body. Clients that treated `200` as success must be updated. |\n| 2 Jul 2026 | Create responses now return the new record's `id`. It was previously `null`. |\n| 2 Jul 2026 | Task and case `stage` now persists on create and update. |\n| 2 Jul 2026 | Contact search now matches multi-word queries such as a full name. |\n| 2 Jul 2026 | Added `GET /api/v2/users`. `assigned_to` is now writable on tasks and notes. |\n| 30 Jun 2026 | Added commission import endpoints. |\n| 16 Jun 2026 | **Breaking.** `ssn`, `tax_id` and `mbi_id` are no longer returned in full. A write still accepts the complete value; a read returns only the last two characters, with everything before them replaced by `*`. Do not use a read value as the input to a later write. |\n| 12 Jun 2026 | **Breaking.** Read endpoints are now filtered to the records the authorizing user can see. Tokens for limited-role users return fewer records than before. |\n| 5 May 2026 | Added case contacts and dependents endpoints, employee create and update, and note delete. |\n| 13 Apr 2026 | Added Medicare fields to cases and benefits, and `sales_status` filtering on the cases list. |\n","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":false,"owner":"10991123","team":913546,"collectionId":"67f16f46-0fc7-44a3-a30c-4cf687f69c5c","publishedId":"2sB3QJMpxP","public":true,"publicUrl":"https://dev.nextagency.com","privateUrl":"https://go.postman.co/documentation/10991123-67f16f46-0fc7-44a3-a30c-4cf687f69c5c","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"},"documentationLayout":"classic-double-column","customisation":{"metaTags":[{"name":"description","value":""},{"name":"title","value":""}],"appearance":{"default":"light","themes":[{"name":"dark","logo":null,"colors":{"top-bar":"212121","right-sidebar":"303030","highlight":"FF6C37"}},{"name":"light","logo":null,"colors":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"FF6C37"}}]}},"version":"8.12.8","publishDate":"2025-10-06T14:32:27.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{"title":"","description":""},"logos":{"logoLight":null,"logoDark":null}},"statusCode":200},"environments":[],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/07bb266eba4b2b0d9fb4d9a6fe7e08373549290813c80cb38fdf810cc416ff12","favicon":"https://nextagency.com/favicon.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"}],"canonicalUrl":"https://dev.nextagency.com/view/metadata/2sB3QJMpxP"}