Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -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?
<!-- Brief description of the change -->

## 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)
2 changes: 1 addition & 1 deletion docs/Authorization/2-legged-oauth/UsingAServiceAccount.md
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions docs/Guides/Advertising/campaignStats.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ title: Example Response
"costMicros": 47000000,
"averageCostPerClickMicros": 712121,
"clickThroughRate": 0.012828,
"currencyCode": "CAD",
"currencyCode": "CAD"
}
}
]
Expand Down Expand Up @@ -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"
}
Expand Down
3 changes: 1 addition & 2 deletions docs/Guides/Advertising/connectedAccount.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ title: Request
},
"query": {
"businessLocation.id": "AG-JT87JWQ7KN",
"filter[provider]": "google",
"filter[provider]": "facebook"
"filter[provider]": "google"
}
}
```
Expand Down
10 changes: 5 additions & 5 deletions docs/Guides/CRM-Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.

11 changes: 4 additions & 7 deletions docs/Guides/Guides-Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---

Expand All @@ -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).



Expand Down
4 changes: 2 additions & 2 deletions docs/Guides/Scim/Guide-to-sync-users-in-vendasta.md
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down
2 changes: 1 addition & 1 deletion docs/Guides/Social/socialProfiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
}
}
```
<!--
Expand Down
71 changes: 71 additions & 0 deletions docs/Overview/APIArchitecture.md
Original file line number Diff line number Diff line change
@@ -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` |
136 changes: 136 additions & 0 deletions docs/Overview/Errors.md
Original file line number Diff line number Diff line change
@@ -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.
4 changes: 2 additions & 2 deletions docs/Overview/Intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ In the body of responses you will find links to related actions and helpful deta
Every request requires an OAuth2 bearer authorization header that was issued by the API Gateway. [Learn to create them](../Authorization/Authorization.md)

### Localization
Translating the content in the platform is crowed sourced and will improve over time. You are encouraged to provide a list of languages that the user can read using the [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) request header. Web browsers will often set this for you by default. If not set `en-US` will be used.
Translating the content in the platform is crowd sourced and will improve over time. You are encouraged to provide a list of languages that the user can read using the [Accept-Language](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language) request header. Web browsers will often set this for you by default. If not set `en-US` will be used.

We will pick the most appropriate locale based on the header and available translations. Resource attributes representing an enum will have both an untranslated `{attribute}Code` and a translated `{attribute}Name` option. Look for the `x-translateable` flag in the documentation. Translatable fields are readonly over API.

Expand Down Expand Up @@ -100,7 +100,7 @@ Content-Type: application/vnd.api+json


### Filters
Most operations that return on a list of data allow you to filter the list using query params in the form of `&filter[fieledName1]=value1&filter[sub.fieledName3]=value2`.
Most operations that return on a list of data allow you to filter the list using query params in the form of `&filter[fieldName1]=value1&filter[sub.fieldName3]=value2`.

### Paging
All operations that return a list of data will let you specify a query param of `page[limit]` to indicate the max number of records you would like returned in a single batch. The body of the response will provide links that you can use to get the next batch without needing to send the filters again. The link will be omitted if not available.
Expand Down
Loading