Shop-Ware REST API v1
Copyright (c) 2017-2020 Shop-Ware Inc
Overview
This describes the resources that comprise the Shop-Ware REST API v1. If you have any problems or requests, please contact support.
Versioning
The initial API version is v1, and is namespaced into each endpoint route, for example: https://api.shop-ware.com/api/v1/tenants/:tenant_id/customers
.
The API version will be increased due to a backwards-incompatible change.
Sandbox Instance
In addition to the production Shop-Ware instance, we provide a sandbox application instance for testing and development. The two environments are identical, except for the following:
- The sandbox instance tracks latest development. New endpoints and attributes will be available on the sandbox environment before they are available on production.
- While the sandbox environment is generally highly available, availability requirements are slightly relaxed.
- The sandbox instance is generally less performant.
- Production and sandbox will use different API secrets for authentication.
The sandbox instance is available at https://api.shop-ware-api-sandbox.com
. The production instance is available at https://api.shop-ware.com
.
Schema
All information is sent and received as JSON data interchange format over HTTPS.
All timestamps will be in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ
. Timestamps in API responses will always include timezone (typically UTC). Always provide timezones in API requests (preferably UTC).
Client Errors
Client errors can be sent as a response to any request method, and indicate an apparent error by the requester.
400 Bad Request
Sending invalid JSON will result in a 400 Bad Request
response.
401 Unauthorized
Sending a request without authentication credentials, or with invalid credentials, will result in a 401 Unauthorized
response. See authentication for details.
404 Not Found
Requesting a non-existent resource will result in a 404 Not Found
response.
422 Unprocessable Entity
Sending invalid fields will result in a 422 Unprocessable Entity
response.
429 Too Many Requests
Exceeding the request rate limit will result in a 429 Too Many Requests
response. See rate limiting for details.
Request Parameters
Many API endpoints accept request parameters. Some parameters are included as part of resource route, such as :tenant_id
:
https://api.shop-ware.com/api/v1/tenants/:tenant_id/customers
Query parameters can be used in GET
requests to scope the response or request specific objects:
https://api.shop-ware.com/api/v1/tenants/:tenant_id/customers?updated_after=2017-05-15T21%3A20%3A37Z
Tenants
In Shop-Ware, tenants represent an account subscription that contain the records of an auto repair business. Most API requests are scoped to a given tenant by the tenant_id
parameter in the request URL. Tenants generally cannot share information, and are isolated from each other. A tenant can have one or more shops, which represent the different business locations (rooftops).
Some records in Shop-Ware are shop-specific, such as repair orders, inventory, vendors, and related resources. Other information is shared between shops, in particular vehicles and customers, and is not shop-specific. Generally, shop-specific resources will have a shop_id
.
Authentication
All Shop-Ware API endpoints require client authorization. Every request must include the X-Api-Partner-Id
and X-Api-Secret
in the HTTP header. These credentials must be requested from Shop-Ware support. Access to each specific tenant must be individually
granted by Shop-Ware Support at the request of an authorized representative of the tenant owner, which may or may not include write
access (requests other than GET
), at the specific request of the tenant owner.
Including invalid credentials, or failing to include any credentials will result in a 401 Unauthorized
response. Attempting to access
a tenant_id
that has not been specifically granted will result in a 404 Not Found
error response, regardless of whether the tenant actually
exists. Sending a request with an HTTP verb other than GET
for a tenant_id
that has not specifically granted write access will result in
a 403 Forbidden
error response.
Example Request
$ curl -v\
-H 'X-Api-Partner-Id: 7f83b909-0e8b-4ee8-8d4d-b1c71f0bb584'\
-H 'X-Api-Secret: MwiknMtHMVFf3hUc-kAViQuXSC7h6qaENnsxZqexE2c'\
-H 'Accept: application/json'\
https://api.shop-ware.com/api/v1/tenants/69/customers
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to api.lvh.me (127.0.0.1) port 5000 (#0)
> GET /api/v1/tenants/69/customers HTTP/1.1
> Host: api.lvh.me:5000
> User-Agent: curl/7.51.0
> X-Api-Partner-Id: 7f83b909-0e8b-4ee8-8d4d-b1c71f0bb584
> X-Api-Secret: MwiknMtHMVFf3hUc-kAViQuXSC7h6qaENnsxZqexE2c
> Accept: application/json
>
< HTTP/1.1 200 OK
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< X-RateLimit-Limit: 100
< X-RateLimit-Remaining: 99
< X-RateLimit-Reset: 1502837110
< Content-Type: application/json; charset=utf-8
< ETag: W/'99914b932bd37a50b983c5e7c90ae93b'
< Cache-Control: max-age=0, private, must-revalidate
< X-Request-Id: f4940e3b-9473-458b-997f-1bc117c7595b
< X-Runtime: 0.915574
< X-Rack-CORS: preflight-hit; no-origin
< Transfer-Encoding: chunked
Rate limiting
All requests from the same IP address will be rate limited. Your current rate limit status will be shown in the HTTP header of each API response. Shop-Ware uses a windowed rate-limiting system. Clients are allowed a fixed number of requests per time window, and the number of requests remaining resets each time window with no carry-over between windows. The headers are defined as follows:
X-RateLimit-Limit: Total number of requests allowed per time window. X-RateLimit-Remaining: Number of requests remaining for this window. X-RateLimit-Reset: Unix time (integer seconds since the Epoch) when the window will reset.
Pagination
Requests that return multiple records will be paginated to 30 records by default.
Further pages can be requested with the page
query parameter.
You can request a custom page size of up to 100 records with the per_page
query parameter.
Result records will be in an array nested under the results
top-level object attribute.
Example Request
curl \
-H 'X-Api-Partner-Id: 7f83b909-0e8b-4ee8-8d4d-b1c71f0bb584'\
-H 'X-Api-Secret: MwiknMtHMVFf3hUc-kAViQuXSC7h6qaENnsxZqexE2c'\
-H 'Accept: application/json'\
https://api.shop-ware.com/api/v1/tenants/4/staffs?page=2&per_page=100
Example Response
{
'results': [
{
'id': 1,
'first_name': 'James',
'last_name': 'Brown',
'advisor': true,
'technician': false,
'active': true,
'created_at': '2017-08-07T01:32:20.811Z',
'updated_at': '2017-08-07T01:32:20.811Z',
'email': 'jbrown@example.com'
}
],
'limit': 1,
'limited': true,
'total_count': 1,
'current_page': 2,
'total_pages': 2
}
Attribute | Type | Description |
---|---|---|
limit |
number | The number of records that are included in this response. |
limited |
boolean | true if the response has been limited to 100 records, false otherwise. |
total_count |
number | The total number of records in all pages. |
current_page |
number | The current page number. Page 1 is the first page. |
total_pages |
number | The total number of pages. |
Filtering by Update After
The updated_after
parameter will return records with an updated_at
that is after the given datetime. Records with the updated_after
parameter will be ordered by their updated_at
field in decending order.
The updated_after
parameter must be in an iso8601 format.
Note that timestamps as stored in the database have sub-millisecond-precision. You are welcome to provide timestamps with only second-precision, just note that a value for updated_after
like 2021-04-05T18:23:47+00:00
(second-precision) will result in a record with updated_at=2021-04-05T18:23:47.123456+00:00
being returned, as .000000
is effectively considered to be the default microseconds value for the filter, if none provided.
Some examples of acceptable formats for updated_after
are below:
2017-08-16T18:23:47+00:00
2017-08-16T18:23:47.123456+00:00
2017-08-16T18:25:54Z
2017-08-16T18:25:54.123456Z
20010203T040506+0700
20010203T040506.123456+0700
2017-05-15T21%3A20%3A37Z
2017-05-15T21%3A20%3A37.123456Z
Example Request
curl \
-H 'X-Api-Partner-Id: 7f83b909-0e8b-4ee8-8d4d-b1c71f0bb584'\
-H 'X-Api-Secret: MwiknMtHMVFf3hUc-kAViQuXSC7h6qaENnsxZqexE2c'\
-H 'Accept: application/json'\
https://api.shop-ware.com/api/v1/tenants/4/staffs?updated_after=2017-01-16T03:33:03Z
Webhooks
Shop-Ware supports webhooks, which allow a callback URL to be configured for asynchronous notification of certain events. Shop-Ware will send a POST request containing information about the event. Each event type shares a common JSON object structure with an event-specific “data” attribute.
Webhooks will generally be delivered immediately following the triggering event. However, there are cases where events will be queued and delivered some time later. Further, events may be delivered simultaneously or out of order, in particular if the events are triggered very close in time.
Up to 20 webhooks can be configured per Partner ID. Shop-Ware webhooks will only deliver to HTTPS URLs, and will not follow redirects. Self-signed certificates are not supported.
Webhook requests may be authenticated by verifying the X-Api-Secret request header, which will be set to the client’s API secret.
Example Webhook Event Request Body for created
and updated
{
'id': '484050ea-df1b-466f-9830-c7c940e73932',
'timestamp': '2019-10-04T15:06:10Z',
'event': 'customer.created',
'payload': {
'type': 'Customer',
'id': 10,
'tenant_id': 69,
'data': {
'id': 10,
'created_at': '2019-10-04T15:06:09Z',
'updated_at': '2019-10-04T15:06:09Z',
'first_name': 'Keith',
'last_name': 'Richards',
'phone': '(555) 555-1234',
'detail': 'New customer',
'address': '123 Main Street',
'city': 'San Diego',
'state': 'CA',
'zip': '92111',
'marketing_ok': true,
'shop_ids': [],
'email': 'keef2@example.com',
'integrator_tags': []
}
}
}
Attribute | Type | Description |
---|---|---|
id |
string | Unique identifier for this event. |
timestamp |
string | Date the event was triggered. |
event |
string | The event type which triggered this webhook (ex. “assignment.updated”). This attribute will use the same syntax as the POST /webhooks events array. |
payload |
object | The payload object of the event. The contents of this object are determined by the type of the event, as specified by the event attribute. |
payload.type |
string | The resource type that triggered this event. One of ‘Assignment’, ‘Category’, ‘Customer’, ‘Staff’, ‘Inventory’, ‘PastRecommendation’, ‘Shop’, ‘Vehicle’, ‘Category’, ‘PaymentTransaction’, ‘Status’, ‘RepairOrder’ or ‘PurchaseRecord’. |
payload.id |
integer | The unique primary key of this resource record. |
payload.tenant_id |
integer | The id of the tenant related to this record. |
payload.data |
object | The object representation of the resource record that triggered this event, which will be identical to what would be received by directly requesting the resource via the REST API. See appropriate REST API endpoint documentation for details. |
Example Webhook Event Request Body for deleted
{
'id': '484050ea-df1b-466f-9830-c7c940e73932',
'timestamp': '2019-10-04T15:06:10Z',
'event': 'status.deleted',
'payload': {
'type': 'Status',
'id': 103,
'tenant_id': 69
}
}
Attribute | Type | Description |
---|---|---|
id |
string | Unique identifier for this event. |
timestamp |
string | Date the event was triggered. |
event |
string | The event type which triggered this webhook (ex. “assignment.deleted”). This attribute will use the same syntax as the POST /webhooks events array. |
payload |
object | The payload object of the event. |
payload.type |
string | The resource type that triggered this event. One of ‘Assignment’, ‘Category’, ‘Customer’, ‘Staff’, ‘Inventory’, ‘PastRecommendation’, ‘Shop’, ‘Vehicle’, ‘Category’, ‘PaymentTransaction’, ‘Status’, ‘RepairOrder’ or ‘PurchaseRecord’. |
payload.id |
integer | The unique primary key of this resource record. |
payload.tenant_id |
integer | The id of the tenant related to this record. |