From 5dbd29d7937664ad8521934f45ed75910070bfa3 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 8 Jun 2026 01:33:07 +0000 Subject: [PATCH 1/2] Improve developer docs: fix bugs, add quickstart guide, expand thin content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix content-type typo in advertising.yaml (vdn → vnd) that would break integrations - Fix invalid JSON in code examples (campaignStats, socialProfiles) - Fix Java syntax error in UsingAServiceAccount.md - Fix typos across 8 files (maintenance, products, lifecycle, fieldName, opportunity, etc.) - Fix escaped quote in SCIM guide JSON examples - Fix garbled UUID in IDP-User-Sync.md example - Add missing API descriptions to advertising and reputation OpenAPI specs - Add Quickstart guide for new developers (end-to-end first API call) - Expand RequestFormat.md from 2 sentences to full JSON:API reference - Replace stale "Coming Soon" gRPC section with link to Vendasta APIs - Add orphaned CRM-Overview.md to table of contents - Fix duplicate filter parameter in connectedAccount guide https://claude.ai/code/session_016Y8YdFJkcoTLKekSce4PrS --- .../2-legged-oauth/UsingAServiceAccount.md | 2 +- docs/Guides/Advertising/campaignStats.md | 4 +- docs/Guides/Advertising/connectedAccount.md | 3 +- docs/Guides/CRM-Overview.md | 10 +- docs/Guides/Guides-Overview.md | 11 +- .../Scim/Guide-to-sync-users-in-vendasta.md | 4 +- docs/Guides/Social/socialProfiles.md | 2 +- docs/Overview/Intro.md | 4 +- docs/Overview/Quickstart.md | 158 ++++++++++++++++++ docs/Overview/RequestFormat.md | 99 +++++++++++ docs/SSO/IDP-User-Sync.md | 2 +- docs/SSO/Overview.md | 2 +- openapi/advertising/advertising.yaml | 8 +- openapi/reputation/reputation.yaml | 2 +- toc.json | 12 +- 15 files changed, 293 insertions(+), 30 deletions(-) create mode 100644 docs/Overview/Quickstart.md diff --git a/docs/Authorization/2-legged-oauth/UsingAServiceAccount.md b/docs/Authorization/2-legged-oauth/UsingAServiceAccount.md index 62bb8f9e..daaf7d0f 100644 --- a/docs/Authorization/2-legged-oauth/UsingAServiceAccount.md +++ b/docs/Authorization/2-legged-oauth/UsingAServiceAccount.md @@ -413,7 +413,7 @@ public class ServiceAccountSample { // The request scope for the token Scope scope = new Scope("profile", "email"); // The token endpoint - URI tokenEndpoint = new URI((string)credentials.get("token_uri"); + URI tokenEndpoint = new URI((String)credentials.get("token_uri")); // Make the token request TokenRequest request = new TokenRequest(tokenEndpoint, bearerGrant, scope); TokenResponse response = TokenResponse.parse(request.toHTTPRequest().send()); diff --git a/docs/Guides/Advertising/campaignStats.md b/docs/Guides/Advertising/campaignStats.md index 84e85097..9310b529 100644 --- a/docs/Guides/Advertising/campaignStats.md +++ b/docs/Guides/Advertising/campaignStats.md @@ -65,7 +65,7 @@ title: Example Response "costMicros": 47000000, "averageCostPerClickMicros": 712121, "clickThroughRate": 0.012828, - "currencyCode": "CAD", + "currencyCode": "CAD" } } ] @@ -94,7 +94,7 @@ title: Request "Content-Type": "application/vnd.api+json" }, "query": { - "connectedAccount.id": "AG-X5FZQG6T25:google:1324354698" + "connectedAccount.id": "AG-X5FZQG6T25:google:1324354698", "startAt": "2021-01-01T00:00:00Z", "endAt": "2021-02-01T00:00:00Z" } diff --git a/docs/Guides/Advertising/connectedAccount.md b/docs/Guides/Advertising/connectedAccount.md index 96b8dfea..99be00f5 100644 --- a/docs/Guides/Advertising/connectedAccount.md +++ b/docs/Guides/Advertising/connectedAccount.md @@ -94,8 +94,7 @@ title: Request }, "query": { "businessLocation.id": "AG-JT87JWQ7KN", - "filter[provider]": "google", - "filter[provider]": "facebook" + "filter[provider]": "google" } } ``` diff --git a/docs/Guides/CRM-Overview.md b/docs/Guides/CRM-Overview.md index 8fa1ff6b..1ed7f82f 100644 --- a/docs/Guides/CRM-Overview.md +++ b/docs/Guides/CRM-Overview.md @@ -3,7 +3,7 @@ The CRM provides a single source of truth for all of your prospect and customer data. Here are a few object types you should be familiar with. ## Companies -A company represents business you sell to. When using a location based product you will need a seperate company record per location. They can be associated in a parent-child relationship. +A company represents a business you sell to. When using a location based product you will need a separate company record per location. They can be associated in a parent-child relationship. ## Contacts Contacts represent a single person. They can be associated with companies in a many-to-many relationship. @@ -12,12 +12,12 @@ Contacts represent a single person. They can be associated with companies in a m An activity is used to track things that happen to a contact and/or company. There are many sub-types such as notes, meetings, calls, and tasks. ## Accounts -Once a company moves from being a lead to a solid oppertunity or sale an account record will be created. It is used to grant access to business app, track payments and activate products. +Once a company moves from being a lead to a solid opportunity or sale an account record will be created. It is used to grant access to business app, track payments and activate products. -Some data is automatically kept in sync between the company and account record. The account has additional fields that are customer manageble which are used to keep online listing profiles (like Google Maps) up to date. +Some data is automatically kept in sync between the company and account record. The account has additional fields that are customer manageable which are used to keep online listing profiles (like Google Maps) up to date. -In our older APIs you may see this refered to as a Sales Account, Account Group, or Business Location. +In our older APIs you may see this referred to as a Sales Account, Account Group, or Business Location. ## Users -Contacts can be turned into Users to grant them access to their Account in Business App. Their name and address will be kept in sync. This allows customers to help keep your CRM data upto date. +Contacts can be turned into Users to grant them access to their Account in Business App. Their name and address will be kept in sync. This allows customers to help keep your CRM data up to date. diff --git a/docs/Guides/Guides-Overview.md b/docs/Guides/Guides-Overview.md index 3a1fba39..84346d14 100644 --- a/docs/Guides/Guides-Overview.md +++ b/docs/Guides/Guides-Overview.md @@ -7,16 +7,13 @@ Automate repetitive tasks within your Vendasta platform instance using our APIs. **[Platform API](https://developers.vendasta.com/platform)** -This is the current standard for building integrations with the Vendasta platform. These APIs are now in *maitenance mode*. Beyond the CRM API there will be little further development on these APIs. +This is the current standard for building integrations with the Vendasta platform. These APIs are now in *maintenance mode*. Beyond the CRM API there will be little further development on these APIs. --- -**gRPC reverse proxy api gateway** - -*Coming Soon!* - -Instead of integrating against external copies of the APIs that power the Vendasta platform, you'll gain access to every action available through the UI via our gRPC plugin. +**[Vendasta APIs](https://developers.vendasta.com/platform)** +A growing set of additional APIs providing access to more Vendasta platform capabilities including Social Posts, Reputation, Meetings, Conversations, Forms, CRM, and more. Check the Vendasta APIs section in the sidebar for the full list. --- @@ -28,7 +25,7 @@ These are not recommended to be used for new integrations. If you already utiliz Allow your SMB users to seamlessly access Vendasta's white-label platform. You can authenticate them within your own platform and then use **OAuth2/OIDC single sign-on (SSO)** to grant access. This is a great option if your customers already have credentials stored in your system, as you can replace Vendasta's Business App login screens with your own by configuring **Identity Provider (IdP) SSO**. ## Build an integration for your clients -Do you have an app which manages data for other businesses that you want to make seamlessly available to your clients through the Vendasta Business App? Then you will want to check out the Guide to [Building Producs & Services in the Platform](https://developers.vendasta.com/vendor/112210c5ddd88-configuring-your-products-and-services) - [Example App Implementation](https://developers.vendasta.com/vendor/463ea876a888b-creating-new-vendor-application#creating-new-vendor-application). +Do you have an app which manages data for other businesses that you want to make seamlessly available to your clients through the Vendasta Business App? Then you will want to check out the Guide to [Building Products & Services in the Platform](https://developers.vendasta.com/vendor/112210c5ddd88-configuring-your-products-and-services) - [Example App Implementation](https://developers.vendasta.com/vendor/463ea876a888b-creating-new-vendor-application#creating-new-vendor-application). diff --git a/docs/Guides/Scim/Guide-to-sync-users-in-vendasta.md b/docs/Guides/Scim/Guide-to-sync-users-in-vendasta.md index 2a5e73f3..2ba5d599 100644 --- a/docs/Guides/Scim/Guide-to-sync-users-in-vendasta.md +++ b/docs/Guides/Scim/Guide-to-sync-users-in-vendasta.md @@ -121,7 +121,7 @@ If the user already exists then it will throw an error. { "type": "work", "streetAddress": "100 Universal City Plaza", - "locality\"": "Hollywood", + "locality": "Hollywood", "region": "CA-SK", "postalCode": "91608", "country": "CA", @@ -316,7 +316,7 @@ If there is no user with the given ID then it would throw an error. { "type": "work", "streetAddress": "100 Universal City Plaza", - "locality\"": "Hollywood", + "locality": "Hollywood", "region": "CA-SK", "postalCode": "91608", "country": "CA", diff --git a/docs/Guides/Social/socialProfiles.md b/docs/Guides/Social/socialProfiles.md index 914237d8..1bfd47d8 100644 --- a/docs/Guides/Social/socialProfiles.md +++ b/docs/Guides/Social/socialProfiles.md @@ -113,7 +113,7 @@ title: Example Response "links":{ "first":"https://prod.apigateway.co/products/social/socialProfiles?filter[businessLocation.id]=AG-F7GHCJ4QCX&page[cursor]=eyJidXNpbmVzc0xvY2F0aW9uIjoiQUctRjdHSENKNFFDWCIsIm9mZnNldCI6MH0=&page[limit]=3", "next":"https://prod.apigateway.co/products/social/socialProfiles?filter[businessLocation.id]=AG-F7GHCJ4QCX&page[cursor]=eyJidXNpbmVzc0xvY2F0aW9uIjoiQUctRjdHSENKNFFDWCIsIm9mZnNldCI6MX0=&page[limit]=3" - }, + } } ``` +> **Tip:** For quick tests you can also use the **Generate Token** button at the top of the Developer Center. + +For examples in other languages see [Obtaining an Access Token](../Authorization/2-legged-oauth/UsingAServiceAccount.md). + +## Step 3: Make Your First API Call + +With your access token, call the user-info endpoint to verify everything is working: + +```sh +curl -X GET "https://sso-api-prod.apigateway.co/oauth2/user-info" \ + -H "Authorization: Bearer YOUR_ACCESS_TOKEN" +``` + +You should receive a response like: + +```json +{ + "sub": "U-d6f69389-350c-465e-ad8a-3c68447fb63a", + "email": "my-service@partner-service-account.apigateway.co", + "updated_at": 1591049766, + "roles": ["partner_service_account"], + "created_at": 1591049766 +} +``` + +## Step 4: Fetch Real Data + +Now try listing business accounts. Replace the partner ID with your own: + +```sh +curl -X GET "https://prod.apigateway.co/platform/salesAccounts?page[limit]=3" \ + -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ + -H "Content-Type: application/vnd.api+json" +``` + +The response follows the [JSON:API](https://jsonapi.org/examples/) format: + +```json +{ + "links": { + "first": "https://prod.apigateway.co/platform/salesAccounts?page[cursor]=abc&page[limit]=3", + "next": "https://prod.apigateway.co/platform/salesAccounts?page[cursor]=def&page[limit]=3" + }, + "data": [ + { + "type": "salesAccounts", + "id": "AG-1234567", + "attributes": { + "name": "Acme Corp", + "customerIdentifier": "CUST-001" + } + } + ] +} +``` + +## Environments + +| Environment | Base URL | +|---|---| +| Production | `https://prod.apigateway.co` | +| Demo/Sandbox | `https://demo.apigateway.co` | + +To get a sandbox environment for testing, contact support@vendasta.com. + +## What's Next? + +- **[Authorization deep dive](../Authorization/Authorization.md)** — Learn about 3-legged OAuth and scopes +- **[Create an account](../Guides/Accounts.md)** — Create and manage business accounts +- **[Sell products](../Guides/Sell/Overview.md)** — Activate products for your accounts via API +- **[CRM API](../Guides/CRM/crm.md)** — Manage contacts, companies, and activities +- **[Set up SSO](../SSO/Overview.md)** — Let your users sign in to Vendasta through your platform +- **[API Reference](../../openapi/platform/platform.yaml)** — Full Platform API reference diff --git a/docs/Overview/RequestFormat.md b/docs/Overview/RequestFormat.md index dfd6a579..c096e28c 100644 --- a/docs/Overview/RequestFormat.md +++ b/docs/Overview/RequestFormat.md @@ -3,3 +3,102 @@ The body of most requests and responses are JSON objects that are formatted according to the [JSON:API](https://jsonapi.org/examples/) standard. Each representation has a `type` field that can be mapped to a single path with the gateway. With the addition of the resource ID it is possible to map any JSON object to its source. + +## Content Type + +Requests and responses use the `application/vnd.api+json` content type. Include this in your request headers: + +``` +Content-Type: application/vnd.api+json +``` + +## Resource Structure + +Every resource is wrapped in a `data` object containing `type`, `id`, and `attributes`: + +```json +{ + "data": { + "type": "salesAccounts", + "id": "AG-1234567", + "attributes": { + "name": "Company Example", + "customerIdentifier": "CUST-5" + } + } +} +``` + +When creating a resource, omit the `id` field — it will be generated by the server and returned in the response. + +## Relationships + +Related resources are expressed under a `relationships` key: + +```json +{ + "data": { + "type": "salesAccounts", + "attributes": { + "name": "Company Example" + }, + "relationships": { + "businessPartner": { + "data": { + "type": "partners", + "id": "ABC" + } + } + } + } +} +``` + +## Sparse Fieldsets + +You can request only specific fields using the `fields` query parameter. This reduces response size and lets the platform warn you about deprecated fields you rely on: + +``` +GET /platform/salesAccounts/AG-1234567?fields[salesAccounts]=name,customerIdentifier +``` + +## Filtering + +Most list operations support filtering via query parameters: + +``` +GET /platform/salesAccounts?filter[name]=Acme&filter[partner.id]=ABC +``` + +See the documentation for each endpoint for the list of supported filters. + +## Pagination + +All list operations support cursor-based pagination using `page[limit]` and `page[cursor]`: + +``` +GET /platform/salesAccounts?page[limit]=25 +``` + +The response includes `links` for navigating between pages: + +```json +{ + "links": { + "first": "https://prod.apigateway.co/platform/salesAccounts?page[cursor]=abc&page[limit]=25", + "next": "https://prod.apigateway.co/platform/salesAccounts?page[cursor]=def&page[limit]=25" + } +} +``` + +The `next` link will be omitted when you have reached the last page. + +## Sorting + +Some list operations support sorting via the `sort` query parameter. Prefix with `-` for descending order: + +``` +GET /platform/salesAccounts?sort=-createdAt +``` + +Check each endpoint's documentation for supported sort fields. diff --git a/docs/SSO/IDP-User-Sync.md b/docs/SSO/IDP-User-Sync.md index 6120d3bf..b6c0d21c 100644 --- a/docs/SSO/IDP-User-Sync.md +++ b/docs/SSO/IDP-User-Sync.md @@ -60,7 +60,7 @@ If the contact information you provide is valid, it will create a new customer r "data": [ { "type": "users", - "id": "U-a1654fed-78d3-4 bd 4-bf39-80203ca5273a", + "id": "U-a1654fed-78d3-4bd4-bf39-80203ca5273a", "attributes": { "givenName": "Chris", "familyName": "Green", diff --git a/docs/SSO/Overview.md b/docs/SSO/Overview.md index 78f33b2b..ef781f32 100644 --- a/docs/SSO/Overview.md +++ b/docs/SSO/Overview.md @@ -25,7 +25,7 @@ Create, update and remove user profiles and permissions in the Vendasta platform [Learn to sync users with your IDP](IDP-User-Sync.md) -## User Lifecycel Management for marketplace apps +## User Lifecycle Management for marketplace apps Create, update and remove user profiles in your marketplace apps based on changes in the Vendasta platform. [Vendor SSO user syncing](https://developers.vendasta.com/vendor/d191b96068b71-sso-o-auth2-3-legged-flow#user-syncing) diff --git a/openapi/advertising/advertising.yaml b/openapi/advertising/advertising.yaml index 5f35fb50..dc996a8c 100644 --- a/openapi/advertising/advertising.yaml +++ b/openapi/advertising/advertising.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Advertising Intelligence REST APIs version: '1.0' - description: '' + description: APIs for retrieving advertising account and campaign data from connected ad platforms including Google, Facebook, and local ads. servers: - url: 'https://prod.apigateway.co/products/advertising' description: Production @@ -23,7 +23,7 @@ paths: content: application/vnd.api+json: schema: - description: '' + description: A list of aggregate advertising statistics across all connected accounts for the specified business location. type: object x-examples: example-1: @@ -93,7 +93,7 @@ paths: content: application/vnd.api+json: schema: - description: '' + description: Aggregate advertising statistics for the specified connected account. type: object x-examples: example-1: @@ -164,7 +164,7 @@ paths: '200': description: OK content: - application/vdn.api+json: + application/vnd.api+json: schema: type: object properties: diff --git a/openapi/reputation/reputation.yaml b/openapi/reputation/reputation.yaml index c31204f9..49e505eb 100644 --- a/openapi/reputation/reputation.yaml +++ b/openapi/reputation/reputation.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Reputation REST APIs version: '1.0' - description: '' + description: APIs for retrieving online reviews collected by the Reputation AI product across 50+ review sources. servers: - url: 'https://prod.apigateway.co/products/reputation' description: Production diff --git a/toc.json b/toc.json index ad6d2a32..48f36888 100644 --- a/toc.json +++ b/toc.json @@ -9,6 +9,11 @@ "title": "Overview", "uri": "docs/Overview/Intro.md" }, + { + "type": "item", + "title": "Quickstart", + "uri": "docs/Overview/Quickstart.md" + }, { "type": "item", "title": "Versioning", @@ -105,7 +110,12 @@ "items": [ { "type": "item", - "title": "CRM", + "title": "CRM Overview", + "uri": "docs/Guides/CRM-Overview.md" + }, + { + "type": "item", + "title": "CRM Developer Guide", "uri": "docs/Guides/CRM/crm.md" }, { From 2c57f1a662b9b46ed2af01028eae27816076609d Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 8 Jun 2026 02:08:07 +0000 Subject: [PATCH 2/2] Add API Architecture guide, Error reference, and TOC restructure - Add API Architecture page explaining gateway APIs vs service APIs, helping developers understand which API layer to use - Add Error reference page documenting HTTP status codes, error codes, error response format, and retry strategies with code example - Add RequestFormat.md and Errors pages to TOC (were missing) - Rename "Vendasta APIs" section to "Service APIs" for clarity - Rename cryptic "Wsp *" entries to "Website Pro *" in TOC - Rename "Crm" to "CRM (Extended)", "Vanalytics" to "Call Tracking & Analytics" - Fix "Wordpress" capitalization to "WordPress" - Move deprecated Business APIs from main navigation to new "Deprecated & Legacy" section alongside Legacy APIs - Improve PR template with docs-specific checklist items - Add cross-links from Quickstart to new Architecture and Errors pages https://claude.ai/code/session_016Y8YdFJkcoTLKekSce4PrS --- .github/PULL_REQUEST_TEMPLATE.md | 12 ++- docs/Overview/APIArchitecture.md | 71 ++++++++++++++++ docs/Overview/Errors.md | 136 +++++++++++++++++++++++++++++++ docs/Overview/Quickstart.md | 3 + toc.json | 53 +++++++----- 5 files changed, 252 insertions(+), 23 deletions(-) create mode 100644 docs/Overview/APIArchitecture.md create mode 100644 docs/Overview/Errors.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f1e270b7..b55fb2bc 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,4 +1,12 @@ @vendasta/external-apis -**TODO**: -- [ ] Review the [pre release checklist](https://vendasta.jira.com/wiki/spaces/API/pages/1651769533/Pre+Release+Checks) +## What changed and why? + + +## Checklist +- [ ] Review the [pre-release checklist](https://vendasta.jira.com/wiki/spaces/API/pages/1651769533/Pre+Release+Checks) +- [ ] If adding/removing pages: `toc.json` updated +- [ ] JSON code examples are valid (no trailing commas, no missing commas) +- [ ] Internal links resolve correctly (test in Stoplight preview if possible) +- [ ] OpenAPI spec changes pass Spectral linting +- [ ] Changelog updated (if applicable) diff --git a/docs/Overview/APIArchitecture.md b/docs/Overview/APIArchitecture.md new file mode 100644 index 00000000..95e00981 --- /dev/null +++ b/docs/Overview/APIArchitecture.md @@ -0,0 +1,71 @@ +--- +tags: [overview, api-architecture] +--- + +# API Architecture + +Vendasta exposes two layers of APIs. Understanding the difference will help you pick the right one for your use case. + +## Gateway APIs (JSON:API) + +These are the **hand-curated REST APIs** documented under the Platform, CRM, and Product sections of this site. They are the recommended starting point for most integrations. + +**Characteristics:** +- Follow the [JSON:API](https://jsonapi.org/examples/) standard (`application/vnd.api+json`) +- Stable versioning with [lifecycle status tracking](Versioning.md) (`x-lifecycle` annotations) +- Consistent pagination, filtering, and error formats across all endpoints +- Rich documentation with examples and guides + +**Sections:** +- **[Platform APIs](../../openapi/platform/platform.yaml)** — Core operations: accounts, orders, users, subscriptions, business categories, automations +- **[CRM APIs](../../openapi/crm/crm.json)** — Contacts, companies, activities, custom objects +- **Product APIs** — [Advertising Intelligence](../../openapi/advertising/advertising.yaml), [Customer Voice](../../openapi/customervoice/customervoice.yaml), [Local SEO](../../openapi/listings/listings.yaml), [Reputation AI](../../openapi/reputation/reputation.yaml), [Social Marketing](../../openapi/social/social.yaml) +- **[SCIM APIs](../../openapi/scim/scim.yaml)** — User provisioning via the SCIM 2.0 standard + +## Service APIs + +These are **additional APIs** auto-generated from Vendasta's internal gRPC services, providing access to capabilities not yet covered by the gateway APIs. + +**Characteristics:** +- Use standard `application/json` format +- Endpoints follow `/v1/` or `/v2/` path patterns +- Schema types reflect their protobuf origins (e.g., `protobufAny`, `rpcStatus`) +- May evolve more rapidly than gateway APIs + +**Available services include:** +- **Social Posts** / **Social Drafts** — Create, manage, and schedule social media content +- **Reputation** — Extended review and NPS management beyond the gateway Reputation AI APIs +- **CRM** — Extended CRM operations beyond the gateway CRM APIs +- **Forms** — Form builder and submission management +- **Meetings** — Meeting scheduling and contact management +- **Conversation** — Messaging and inbox management +- **Sales Orders** — Order processing and management +- **Listing Products** — Listing distribution product management +- **Multi Location Analytics** — Cross-location reporting +- **Vanalytics** — Call tracking and conversation analytics +- **Composer** — Content composition +- **Website** — WordPress hosting, site monitoring, and management (Website Pro) + +## Which Should I Use? + +| Scenario | Recommended | +|---|---| +| New integration, standard CRUD operations | Gateway APIs | +| Account management, orders, user provisioning | Gateway APIs (Platform) | +| CRM contacts, companies, activities | Gateway APIs (CRM) | +| Social post scheduling and management | Service APIs (Social Posts) | +| Features not available in gateway APIs | Service APIs | +| Building on a standard like SCIM or JSON:API | Gateway APIs | + +When both layers cover similar functionality (e.g., Reputation, CRM), the gateway APIs provide a more stable, better-documented interface. The service APIs offer broader coverage when you need capabilities the gateway doesn't expose yet. + +## Authentication + +Both API layers use the same OAuth2 authentication. An access token obtained via [2-legged OAuth](../Authorization/2-legged-oauth/Overview.md) works with both gateway and service APIs. See the [Authorization guide](../Authorization/Authorization.md) for details. + +## Environments + +| Environment | Gateway Base URL | Service API Base URL | +|---|---|---| +| Production | `https://prod.apigateway.co` | `https://prod.apigateway.co` | +| Demo/Sandbox | `https://demo.apigateway.co` | `https://demo.apigateway.co` | diff --git a/docs/Overview/Errors.md b/docs/Overview/Errors.md new file mode 100644 index 00000000..5c2345cd --- /dev/null +++ b/docs/Overview/Errors.md @@ -0,0 +1,136 @@ +--- +tags: [overview, errors, troubleshooting] +--- + +# Errors + +When an error occurs, the API returns a 4XX or 5XX HTTP status code. The response body contains a list of error objects with details to help you diagnose and fix the issue. + +## Error Response Format + +Errors follow the [JSON:API error format](https://jsonapi.org/format/#errors): + +```json +{ + "errors": [ + { + "status": "422", + "code": "MalformedRequestBody", + "title": "Malformed request body", + "detail": "Could not deserialize terms from body: unexpected comma at line 20", + "meta": { + "resourceType": "terms", + "paramValue": "unexpected comma at line 20" + }, + "source": { + "parameter": "page[size]" + }, + "links": { + "about": { + "href": "https://prod.apigateway.co/docs/errorTypes/MalformedRequestBody" + }, + "docs": { + "href": "https://prod.apigateway.co/docs/#operation/get-terms-type" + } + } + } + ] +} +``` + +### Error Object Fields + +| Field | Description | +|---|---| +| `status` | The HTTP status code as a string | +| `code` | A machine-readable error code identifying the specific error type | +| `title` | A short, human-readable summary of the error | +| `detail` | A more specific explanation of what went wrong | +| `source.parameter` | The query parameter that caused the error (when applicable) | +| `source.pointer` | A JSON pointer to the request body field that caused the error (when applicable) | +| `meta` | Additional context about the error | +| `links.about` | A URL with more information about this error type | +| `links.docs` | A URL to the documentation for the operation that was called | + +## HTTP Status Codes + +### Client Errors (4XX) + +| Status | Meaning | Common Causes | +|---|---|---| +| `400` | Bad Request | Malformed JSON, invalid content type, missing required fields | +| `401` | Unauthorized | Missing or expired access token, invalid credentials | +| `403` | Forbidden | The access token lacks the required scope, or the service account doesn't have permission for this resource | +| `404` | Not Found | The resource ID doesn't exist, or the endpoint path is incorrect | +| `409` | Conflict | The resource already exists (e.g., creating a customer with a duplicate identifier) | +| `422` | Unprocessable Entity | The request body is valid JSON but contains invalid values (wrong type, out-of-range, unsupported enum value) | +| `429` | Too Many Requests | You've exceeded the rate limit. Implement exponential backoff and retry. | + +### Server Errors (5XX) + +| Status | Meaning | What To Do | +|---|---|---| +| `500` | Internal Server Error | Retry with exponential backoff. If persistent, contact support. | +| `502` | Bad Gateway | Temporary infrastructure issue. Retry after a short delay. | +| `503` | Service Unavailable | The service is temporarily overloaded or under maintenance. Retry with backoff. | + +## Common Error Codes + +### Request Errors + +| Code | Status | Description | +|---|---|---| +| `MalformedRequestBody` | 422 | The request body could not be parsed. Check for syntax errors in your JSON. | +| `QueryParameterBadValue` | 422 | A query parameter has an invalid value. The `source.parameter` field indicates which one. | + +### Resource Errors + +| Code | Status | Description | +|---|---|---| +| `NotReady` | 422 | A dependent resource is not yet ready. This commonly happens when creating an order immediately after creating a new sales account. Retry with exponential backoff — the account is typically ready within 5 seconds. | +| `NotFound` | 404 | The requested resource does not exist. Verify the ID and endpoint path. | + +### Authentication Errors + +| Code | Status | Description | +|---|---|---| +| `Unauthorized` | 401 | The access token is missing, expired, or invalid. Obtain a new token using the [Authorization guide](../Authorization/Authorization.md). | +| `Forbidden` | 403 | The access token is valid but lacks the required scope. Check the `scope` parameter when requesting your token. | + +## Handling Errors + +### Retry Strategy + +For transient errors (`429`, `500`, `502`, `503`, and `NotReady`), implement exponential backoff: + +1. Wait 1 second, then retry +2. If it fails again, wait 2 seconds +3. Then 4 seconds, 8 seconds, etc. +4. Give up after 5 attempts + +```python +import time +import requests + +def call_with_retry(method, url, **kwargs): + for attempt in range(5): + response = method(url, **kwargs) + if response.status_code in (429, 500, 502, 503): + time.sleep(2 ** attempt) + continue + if response.status_code == 422: + errors = response.json().get("errors", []) + if any(e.get("code") == "NotReady" for e in errors): + time.sleep(2 ** attempt) + continue + return response + return response +``` + +### Error Responses May Contain Multiple Errors + +A single request can produce multiple errors. Always iterate over the full `errors` array rather than only reading the first entry. + +### Use the `links` Object + +Error responses include `links.about` URLs that provide additional context for each error type. These can be useful for debugging and for building user-facing error messages. diff --git a/docs/Overview/Quickstart.md b/docs/Overview/Quickstart.md index faf376f3..6fac469a 100644 --- a/docs/Overview/Quickstart.md +++ b/docs/Overview/Quickstart.md @@ -150,6 +150,9 @@ To get a sandbox environment for testing, contact support@vendasta.com. ## What's Next? +- **[API Architecture](APIArchitecture.md)** — Understand the two API layers and which to use +- **[Request Format](RequestFormat.md)** — JSON:API conventions, pagination, filtering, and sorting +- **[Error Handling](Errors.md)** — Error codes, HTTP statuses, and retry strategies - **[Authorization deep dive](../Authorization/Authorization.md)** — Learn about 3-legged OAuth and scopes - **[Create an account](../Guides/Accounts.md)** — Create and manage business accounts - **[Sell products](../Guides/Sell/Overview.md)** — Activate products for your accounts via API diff --git a/toc.json b/toc.json index 48f36888..03948e50 100644 --- a/toc.json +++ b/toc.json @@ -14,6 +14,21 @@ "title": "Quickstart", "uri": "docs/Overview/Quickstart.md" }, + { + "type": "item", + "title": "API Architecture", + "uri": "docs/Overview/APIArchitecture.md" + }, + { + "type": "item", + "title": "Request Format", + "uri": "docs/Overview/RequestFormat.md" + }, + { + "type": "item", + "title": "Errors", + "uri": "docs/Overview/Errors.md" + }, { "type": "item", "title": "Versioning", @@ -286,15 +301,6 @@ "title": "Platform APIs", "uri": "openapi/platform/platform.yaml" }, - { - "type": "divider", - "title": "Business" - }, - { - "type": "item", - "title": "Business APIs", - "uri": "openapi/business/business.yaml" - }, { "type": "divider", "title": "Products" @@ -355,11 +361,11 @@ }, { "type": "divider", - "title": "Vendasta APIs" + "title": "Service APIs" }, { "type": "group", - "title": "Vendasta APIs", + "title": "Service APIs", "items": [ { "type": "item", @@ -373,17 +379,17 @@ }, { "type": "item", - "title": "Wsp Support Tools", + "title": "Website Pro Support Tools", "uri": "openapi/openapi_external_docs/wsp_support_tools.openapi.json" }, { "type": "item", - "title": "Wsp Admin Center", + "title": "Website Pro Admin Center", "uri": "openapi/openapi_external_docs/wsp_admin_center.openapi.json" }, { "type": "item", - "title": "Wordpress Hosting", + "title": "WordPress Hosting", "uri": "openapi/openapi_external_docs/wordpress_hosting.openapi.json" }, { @@ -413,7 +419,7 @@ }, { "type": "item", - "title": "Crm", + "title": "CRM (Extended)", "uri": "openapi/openapi_external_docs/crm.openapi.json" }, { @@ -423,22 +429,22 @@ }, { "type": "item", - "title": "Vanalytics", + "title": "Call Tracking & Analytics", "uri": "openapi/openapi_external_docs/vanalytics.openapi.json" }, { "type": "item", - "title": "Wsp Site Info", + "title": "Website Pro Site Info", "uri": "openapi/openapi_external_docs/wsp_site_info.openapi.json" }, { "type": "item", - "title": "Wsp Monitor", + "title": "Website Pro Monitor", "uri": "openapi/openapi_external_docs/wsp_monitor.openapi.json" }, { "type": "item", - "title": "Wsp Wp Manager", + "title": "Website Pro Manager", "uri": "openapi/openapi_external_docs/wsp_wp_manager.openapi.json" }, { @@ -455,11 +461,16 @@ }, { "type": "divider", - "title": "Legacy" + "title": "Deprecated & Legacy" }, { "type": "item", - "title": "Overview", + "title": "Business APIs (Deprecated)", + "uri": "openapi/business/business.yaml" + }, + { + "type": "item", + "title": "Legacy APIs", "uri": "https://developers.vendasta.com/api/legacy" } ]