Getting Started Edit
Welcome to the official Merchi API documentation page. This API document is designed for those interested in developing for Merchi.
In most cases, we recomend using one of our prebuilt SDK libraries, which are discussed first. They are available for TypeScript, JavasScript, and python.
However, if you do not like them, or one is not available for your preferred programming language, you can also talk directly to our REST API, which is also documented here.
Typescript Edit
An SDK is available for typescript.
Getting Started Edit
The typescript SDK is available from github. Some dependencies are required,
which can be installed with either yarn
or npm
at your preference.
git clone https://github.com/merchisdk/sdk.git
cd typescript
yarn
git clone https://github.com/merchisdk/sdk.git
cd typescript
npm install
The Merchi object Edit
All functionality is available via the Merchi
class. Your first step
when using the typescript SDK must be to create an instance of this class.
Most types of requests against the Merchi API need to be authenticated.
If your code will be running in a web browser environment, the Merchi
object will automatically fetch the sessiont token of the currently
logged in user from the Merchi cookie. Alternatively you can provide
the optional sessionToken
argument to the Merchi
constructor. For
example, you could put something like this into a file named index.ts
.
You may need to adjust the import path in the examples, if you have not placed the typescript SDK into “merchisdk/typescript/”.
import { Merchi } from 'merchisdk/typescript/src/merchi';
const sessionToken = "rk1fGoPW7cyxa8cCLR45CigUtjkO1iCWWuLrK08CDaYD2gHoPHYtF7KsfTgmFcwl8tOyQssaIchgzbTSarjk8A";
const merchi = new Merchi(sessionToken);
Compiling Edit
For large projects, you may want to use a bundler like webpack, however
for getting started, the code compiles just fine with the typescript
compiler alone. The following command, for example, will create an
output file named index.js
, assuming you have written some code in a file named index.ts
. The resulting output can be added directly to your website.
tsc index.ts
<script type="application/javascript" src="index.js"></script>
Listing Entities Edit
Merchi breaks up entities into different types, which loosely corrospond to
REST resources. For each type, there is normally many specific entities
available. Once you have set up the merchi
object, you can get an array
of entities with the list
method. For example, here is how to get
an array of ‘categories’ in the system (categories are groupings of products):
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
merchi.Categories.list().then((result) => {
for const (category of result.items) {
console.log(category.id, category.name);
}
});
Fetching a Single Entity Edit
Almost every entity in Merchi is referenced by its id
.
Once you have the id of an object, you can fetch that entity specifically
using the get
static method:
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
const categoryId = 42;
const myCategory = merchi.Categories.get(categoryId);
.then(() => {
console.log(myCategory.name);
});
Creating a New Entity Edit
New entities can be added to the system with the create
method.
First create a new SDK object using the constructor given by the Merchi
object, then set up some values on the new object, and then call create
.
Creating and editing javascript/typescript objects locally has no effect on the server. Only after you call create
will the object actually be stored with merchi via network request.
You do not need to assign an id
when setting up the object, merchi will create one for the new object automatically.
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
const newCategory = new merchi.Categories();
newCategory.name = "canned food";
newCategory.create().then(() => {
console.log("The new categories id is: " + newCategory.id);
});
Editing an Entity Edit
Existing entities can be edited using the save
method.
First edit the attributes of the object locally, ensure that the id
attribute is set, and then call save
.
You can use the objects returned by list
or get
for editing as those objects will have their id
filled in. But if you already know the id
of the entity that you wish to edit, there is no need to first fetch the entity from the server before editing, you can specify the id
directly.
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
const categoryToEdit = new merchi.Categories();
categoryToEdit.id = 42;
categoryToEdit.name = "dry food"; // make a correction to the name
categoryToEdit.save().then(() => {
console.log("ok, the category name was edited.");
});
Deleting an Entity Edit
Entities can be deleted via the delete
method.
As with editing, if you know the id of the object, you do not have to fetch it before deleting.
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
const categoryToDelete = new merchi.Categories();
categoryToDelete.id = 42;
categoryToDelete.delete().then(() => {
console.log("ok, the category with id 42 was deleted.");
});
Creating Nested entities Edit
Entities can have relationships to other entities.
For example, categories are always linked to a domain
, which is the Merchi
name for a store.
When creating an entity, you can attach a Merchi Domain
object to the
category object, in order to specify when domain it should be attached to.
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
const newCategory = new merchi.Categories();
const existingDomain = new merchi.Domains();
existingDomain.id = 42; // note: this id already exists
newCategory.domain = existingDomain;
newCategory.name = "vegetables";
newCategory.create().then(() => {
console.log("ok, new vegetables category created on domain 42");
});
Embedding Edit
Because entities can be nested arbitrarily deeply (and indeed, cyclic references are possible), the get
and list
methods do not, by default, fetch nested entities from the server. Only scalar properties (strings, numbers, dates, …) are included.
It is possible however to request that the server also include specific
nested entities, to a specific depth using the embed
parameter, as in the following example.
On a newly fetched category category.domain
will be undefined
, even if the category has a domain on the server. undefined
means that the domain has not been included, or updated locally. If the category did not have a domain at all, category.domain
would instead be null
. ‘null and
undefined` thus have seperate meanins in the merchi sdk library.
The following example shows only get
, but the embed parameter can be used with both get
and list
methods.
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
const embed = {'domain': {'theme': {}}};
merchi.Categories.get(42, {embed: embed}).then((category) =>
const themeId = category.domain.theme.id;
console.log('the id of the theme of the domain of category 42 is: ' + themeId);
});
Nested Editing Edit
Calling save
on an entity will also automatically save any local changes to
attached nested entities.
In this example, we edit the name of a store “through” the category object:
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
const category = new merchi.Categories();
category.id = 12; // assume we already have the entity id's
const domain = new merchi.Domains();
domain.id = 42;
category.domain = domain;
domain.domain = "new-store.example.com"; // newly chosen name
category.save().then(() => {
console.log("ok, the category and domain are both updated.");
});
Types vs Constructors Edit
To work around a small limitation in typescript, the entitiy types are seperated from their constructors. If you want to list or create entities, it must always be done through the constructor attached to the Merchi object. The types, however, are imported from the ‘entities’ directory. The following example demonstrates:
Never try to directly instantiate the imported types, always go through the Merchi object.
import { Merchi } from 'merchisdk/typescript/src/merchi';
import { Category } from 'merchisdk/typescript/src/entities/category';
const merchi = new Merchi();
const category: Category = new merchi.Category();
Pagination Edit
As there may be tens or hundreds of thousands of some types of entities,
list
will not return them all at once, but rather it will return one
“page” of results.
The limit
option controls how many results will be returned per page
(further limited by backend-enforced limits, and how many entities are
actually available). It defaults to 25 if not specified.
The offset
option controls how many entities to skip over. For example,
if the limit is set to 10, setting offset to 20 will give you the third
page. It defaults to zero if not not specified.
Additionally, the ListMetadata
type is available on the response of
a call to list
, which contains information about how many entities where
returned to this query, and how many are available in total (if the limit
were infinite and the offset were zero).
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
merchi.Categories.list({offset: 10,
limit: 10).then((result) => {
const categories = result.items;
const info = result.metadata;
console.log("Categories returned: " + info.count);
console.assert(categories.length === info.count, "oh no!");
console.log("Categories available: " + info.available);
});
Searching Edit
Most entities also accept a q
parameter for searching or filtering by
keywords.
The following example shows how to find products related to eggs (the product might have the word egg in it’s name, or description, or might be in a category named egg, or so on).
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
merchi.Products.list({q: "egg").then((result) => {
for (const product of result.items) {
console.log(product.name);
}
});
Filtering Edit
In addition to straight search, many more specific filtering parameters
are available. For example the inDomain
filter restricts list results
to only those from a specific domain, and the tags
filter restricts
list results to only those with a specific Tag added. The exact list
of supported filters varies by entity. For a complete list, see the
Filtering Reference.
import { Merchi } from 'merchisdk/typescript/src/merchi';
const merchi = new Merchi();
merchi.Products.list({tags: ["big", "blue"]).then((result) => {
for (const product of result.items) {
console.log(product.name);
}
});
Error Handling Edit
As the typescript API uses javascript Promises, errors can be caught using
promise.catch()
The error object received will be an instance of ApiError
;
import { Merchi } from 'merchisdk/typescript/src/merchi';
import { ApiError } from 'merchisdk/typescript/src/request';
const merchi = new Merchi();
merchi.Categories.get(42)
.then(() => {
console.log("ok, got a category");
})
.catch((err: ApiError) => {
console.error(`error: ${err.errorCode} ${err.statusCode} ${err.errorMessage}`)
});
});
Other Entities Edit
The examples so far have mostly used products and categories. You may be wondering what other entities exist. A complete list is available in the API reference.
JavaScript Edit
In most cases, we recomend you use our Typescript SDK instead. It is newer, uses newer, more convenient programming techniques, and, of course, being typescript, allows for static typechecking.
Nonetheless, a straight JavaScript version also exists, and is still maintained. One advantage of the JavaScript library is that it will work directly in browsers with no need to setup a compiler toolchain.
Getting Started Edit
The latest version of the javascript SDK is available, minified at:
https://merchi.co/static/js/dist/merchi.js
You can download it and include it in your website or other project, but you are also welcome to hotlink it directly.
Unminified source code is also available here:
https://github.com/merchisdk/sdk/tree/master/javascript
<script type="javascript" src="https://merchi.co/static/js/dist/merchi.js">
</script>
The Merchi object Edit
All functionality is contained in a Merchi object which must manually be initialised. This helps with namespacing. The remainder of the examples in this document will assume that you have already set up a merchi
object as follows:
const merchi = SDK.merchi("https://api.merchi.co/", "https://websockets.merchi.co/");
Fluent API Edit
Entities in the javascript SDK (unlike the typescript SKD) use a fluent style API.
That means that to get the value of an attribute, you must call a method with that name, giving no arguments, and it will return the value.
To set the value, you must call the same method, but providing the new value. When setting a value, the original object will be returned, which lets you ‘chain’ attribute setting calls.
// getting and setting
const domain = new merchi.Domain()
console.assert(domain.domain() === undefined, "attribute not yet set");
const name = "new-value.example.com";
const domain2 = domain.domain(name);
console.assert(domain2 === domain, "the original domain is returned");
console.assert(domain.domain() === name, "attribute has now been set");
// example of chaining multiple sets and a single get into one line
const logoUrl = domain.domain("even-newer-value.example.com")
.smsName("sms.example.com")
.enableSmsNotifications(true)
.enableEmailNotifications(false)
.logoUrl()
console.assert(domain.enableSmsNotifications(), "was set to true");
console.assert(!domain.enableEmailNotifications(), "was set to false");
Listing Entities Edit
A list of entities can be retrieved by taking the entity name in mixedCase and calling the get
function on it.
Note that callbacks must be provided to get the result.
function onSuccess(products) {
console.log("Ok, got some products!");
for (const product of products) {
console.log(product.id());
}
}
const onError = console.error.bind(console);
const parameters = {};
merchi.products.get(onSuccess, onError, parameters);
Fetching a single Entity Edit
The API for fetching a single entity is different to that in the typescript
API. You must first create an entity object locally, and then set the id
value, and call get
on it.
Success and failure callbacks should be provided in order to know when the operation is complete, but it is the original provided entity that gets “filled in” with data from the server.
const product = new merchi.Product()
product.id(42); // we want the product with id 42.
function onSuccess() {
// at this point, `product` has been updated from the Merchi server.
console.log(`the product name is: ${product.name()}`);
}
const onError = console.error.bind(console);
product.get(onSuccess, onError); // this call makes the network request
Creating a new entity Edit
As with fetching, to create a new entity on the server, you must first
create a new entity object locally in javascript. Instead of filling in
the objects id
, you should fill in the data that you want to provide to
the new object, and then call create
. Like the other method in the
javascript SDK, create
takes onSuccess
and onError
callbacks to
let you know when the operation has completed.
const newProduct = new merchi.Product()
newProduct.name("Beans"); // we want to create a new prodcut for beans
newProduct.description("beans are a delicious legume");
function onSuccess() {
// at this point, the new product exists on the merchi server
console.log(`the product has been created with id ${newProduct.id()}`);
}
const onError = console.error.bind(console);
newProduct.create(onSuccess, onError); // this call makes the network request
Editing an Entity Edit
The method for editing values on the server follows the same pattern as
the others. It is named patch
after the HTTP method that it uses.
First, a javascript object should be created locally. Then, both the
id
primary key, and the attributes that you want to edit should be set,
and then you may call patch
. Like the others, patch
accepts callbacks
to let you know when the operation has completed.
const existingProduct = new merchi.Product()
existingProduct.id(42); // we want to edit the product with id 42
existingProduct.name("lentils"); // we want to change its name to lentils
function onSuccess() {
console.log("the product has been edited.");
}
const onError = console.error.bind(console);
existingProduct.patch(onSuccess, onError); // this call makes the network request
Deleting an Entity Edit
To remove an entity from the server, you must create a javascript object
locally, set it’s id
attribute, and then call the destroy
method.
const existingProduct = new merchi.Product()
existingProduct.id(42); // we want to delete the product with id 42
function onSuccess() {
console.log("the product is gone");
}
const onError = console.error.bind(console);
existingProduct.destroy(onSuccess, onError); // this call makes the network request
Creating Nested Entities Edit
As with the typescript SDK, nested entities can be created at once. For example, you might create a product and its category in the same request.
const newProduct = new merchi.Product();
newProduct.name("lime");
newProduct.description("limes are green");
const newCategory = new merchi.Category();
newCategory.name("fruits");
// note that an array is provided as products may be in
// multiple categories.
newProduct.categories([newCategory]);
function onSuccess() {
console.log("the product and category both now exist");
}
const onError = console.error.bind(console);
newProduct.create(onSuccess, onError); // this call makes the network request
Pagination Edit
As there may be tens or hundreds of thousands of some types of entities, listing them will not return them all at once, but rather it will return one “page” of results.
The limit option controls how many results will be returned per page (further limited by backend-enforced limits, and how many entities are actually available). It defaults to 25 if not specified.
The offset option controls how many entities to skip over. For example, if the limit is set to 10, setting offset to 20 will give you the third page. It defaults to zero not not supplied.
Attached to the result array sent to the success callback is also a meta
object containing information about how many results in total are available.
function onSuccess(products) {
console.log(`Got ${products.length} products`);
console.log(`${products.meta.available} products are available`);
console.log(products);
console.assert(products.length == products.meta.count);
console.assert(products.meta.limit == 2);
console.assert(products.meta.offset == 3);
}
const onError = console.error.bind(console);
merchi.products.get(onScuccess, onError, {offset: 3,
limit: 2});
Searching Edit
Most entities also accept a q
parameter in their list method, which
allows you to filter by search terms. The following example shows how
to search for products related to eggs (the returned products might have
the word egg in their names, or descriptions, or might be in a category
named egg, or so on).
function onSuccess(products) {
for (const product of products) {
console.log(product.name());
}
}
const onError = console.error.bind(console);
merchi.products.get(onSuccess, onError, {q: "egg"});
Embedding Edit
Because entities can be nested arbitrarily deeply (and indeed, cyclic references are possible), the fetching and listing methods do not, by default, fetch nested entities from the server. Only scalar properties (strings, numbers, dates, …) are included.
It is possible however to request that the server also include specific
nested entities, to a specific depth using the embed
parameter, as in the following example.
On a newly fetched category category.domain()
will be undefined
, even if the category has a domain on the server. undefined
means that the domain has not been included, or updated locally. If the category did not have a domain at all, category.domain()
would instead be null
. ‘null and
undefined` thus have seperate meanins in the merchi sdk library.
The following example shows only fetching a single entity, but the embed parameter can also be used when listing entities.
const category = new merchi.Category()
category.id(42);
function onSuccess() {
const themeId = category.domain().theme().id();
console.log('the id of the theme of the domain of category 42 is: ' + themeId);
}
const onError = console.error.bind(console);
const embed = {'domain': {'theme': {}}};
merchi.categories.get(onSuccess, onError, {embed: embed});
Filtering Edit
In addition to straight search, many more specific filtering parameters
are available. For example the inDomain
filter restricts list results
to only those from a specific domain, and the tags
filter restricts
list results to only those with a specific Tag added. The exact list
of supported filters varies by entity. For a complete list, see the
Filtering Reference.
function onSuccess(products) {
for (const product of products) {
console.log(product.name());
}
}
const onError = console.error.bind(console);
merchi.products.get(onSuccess, onError, {tags: "big,blue"});
Completeness Edit
The typescript SDK is used internally more heavily than the javascript and PHP SDK’s. It may consequently also be kept more up to date. The other SDK’s are nonetheless fully suppported. If you happen to come across any missing feature, please contact us and we should be able to add it reasonably quickly.
Python Edit
An SDK is available for python.
Getting Started Edit
The python SDK is available from github. Only python3 is supported. Some dependencies are required, which can be installed with pip.
git clone https://github.com/merchisdk/sdk.git
cd python
python3 -m venv venv
source venv/bin/activate
pip install - r requirements/dev.txt
Configuration Edit
The python SDK requires some configuration before use.
The rest of this documentation assumes that you have already configured the SDK according to the instructions in this section.
The request class must be subclassed. In the subclass, set up the server
and host
values. You can optionally also provide a session_token
cookie, if the request should be authenticated as a specific user. The entity class’s request class must then be set to the new subclass. The following example demonstrates:
import sdk.python.request
import sdk.python.entities
class ApiRequest(sdk.python.request.Request):
def __init__(self, forbid_auto_update=False):
super(ApiRequest, self).__init__()
self.server = "https://api.merchi.co/"
self.host = "api.merchi.co"
self.cookies['session_token'] = flask.request.cookies.get('session_token')
sdk.python.entities.Entity.request_class = ApiRequest
Listing Entities Edit
Merchi breaks up entities into different types, which loosely corrospond to REST resources. For each type, there is normally many specific entities available. For example, here is how to get an array of product categories from the server:
import sdk.python.categories
categories, _ = sdk.python.categories.categories.fetch()
print(categories)
Fetching a Single Entity Edit
Almost every entity in merchi is references by its id. Once you have the id of an object, you can fetch that entity specifically using the fetch static method.
Note the differences from listing above. Listing uses the plural, snake_cased entity name and calls fetch
with no arguments, where as fetching takes the CamelCased singular entity name and calls fetch
on it with the id
as its argument.
from sdk.python.categories import Category
category = Category.fetch(42)
print(category)
Creating a New Entity Edit
New entities can be added to the system with the create
method.
First create a new SDK object for the entity, then set up some values on the new object, and then call create.
Creating and editing objects locally has no effect on the server. Only after you call create
will the object actually be stored with merchi.
You do not need to assign an id
when setting up the object, merchi will create one for the new object automatically.
from sdk.python.categories import Category
new_category = Category()
new_category.name = "canned food"
new_category.create()
print(f"The new category id is: {category.id}")
Deleting an Entity Edit
Entities can be deleted via the destroy
method.
If you know the id of the entity you do not have to fetch it before deleting.
from sdk.python.categories import Category
old_category = Category()
old_category.id = 42
old_category.destroy()
print(f"Ok, the category was deleted")
Editing an Entity Edit
Existing entities can be edited using the update
method.
First edit the attributes of the object locally, then call update
You cna use the objects returned by fetch
for editing, but if you already know the id
of the entity that you wish to edit, there is no need to first fetch the entity from the server before editing; you can specify the id
directly.
from sdk.python.categories import Category
existing_category = Category()
existing_category.id = 42
existing_category.name = "dry food" # make a correction to the name
existing_category.update()
print("Ok, the category name was edited")
Creating Nested Entities Edit
Entities can have relationships to other entities.
For example, categories are always linked to a domain, which is the merchi name for a store.
When creating an entity you can attach a merchi Domain
object to the
category object, on order to specify which domain it should be attached to.
from sdk.python.categories import Category
from sdk.python.domains import Domain
new_category = Category()
existing_domain = Domain()
existing_domain.id = 42 # note: this id already exists
new_category.domain = existing_domain
new_category.name = "vegetables"
new_category.create()
print("Ok, new vegetables category created on domain 42")
Embedding Edit
Because entities can be nested arbitrarily deeply fetch
does not, by
default, fetch nested entities from the server. Only scalar properties
(strings, numbers, dates, …) are included.
It is possible however to request that the server also include specific nested entities using the embed parameter, as in the following example.
On a newly fetched (or locally created) Category
, category.domain
will
be None
, even if the category has a domain on the server. You must
request that the domain be embedded in order to know whether the value
is truly null, or just locally unavailable.
The following example shows using embed only with fetching a single entity, but you can also supply the embed parameter when listing multiple entities.
from sdk.python.categories import Category
embed = {'domain': {'theme': {}}}
category = Category.fetch(42, embed=embed)
theme_id = category.domain.theme.id
print(f"The id of the theme of the domain of category 42 is: {theme_id}")
Nested editing Edit
Calling update
on an entity will also automatically save any local
changes to attached nested entities.
In this example, we edit the name of a domain “through” the category object.
from sdk.python.categories import Category
from sdk.python.domains import Domain
category = Category()
category.id = 12 # assume that we already have the entities ids
domain = Domain()
domain.id = 42
category.domain = domain
domain.domain = "new-store.example.com" # newly chosen name
category.update()
print("Ok, the category and domain are both updated.")
Pagination Edit
As there may be tens or hundreds of thousands of some types of entities, listing them will not return them all at once, but rather it will return one “page” of results.
The limit
option controls how many results will be returned per page
(further limited by backend-enforced limits, and how many entities are
actually available). It defaults to 25 if not specified.
The offset
option controls how many entities to skip over. For example,
if the limit is set to 10, setting offset to 20 will give you the third
page. It defaults to zero if not specified.
Additionally the PageSpecification
is available as the second return
value from a listing call to fetch
, which contains information about
how many entities where returned to this query, and how many are available
in total (if the limit where infinite and the offset where zero).
import sdk.python.categories
query = {"limit": 10,
"offset": 10}
categories, info = sdk.python.categories.categories.fetch(query=query)
print(f"Categories returned: {info.count}")
assert len(categories) == info.count
print(f"Categories available: {info.available}")
Searching Edit
Most entities also accept a q
parameter for searching or filtering by
keywords.
The following example shows how to find products related to eggs (the product might have the word egg in it’s name, or description, or might be in a category named egg, or so on).
import sdk.python.categories
query = {"q": "egg"}
categories, _ = sdk.python.categories.categories.fetch(query=query)
for category in categories:
print(category.name)
Filtering Edit
In addition to straight search, many more specific filtering parameters
are available. For example the in_domain
filter restricts list results
to only those from a specific domain, and the tags
filter restricts
list results to only those with a specific Tag added. The exact list
of supported filters varies by entity. For a complete list, see the
Filtering Reference.
import sdk.python.products
query = {"tags": '["big", "blue"]'}
products, _ = sdk.python.product.products.fetch(query=query)
for product in products:
print(product.name)
Error Handling Edit
The python SDK raises python.util.api_error.ApiError
in case of failure.
import sdk.python.products
from sdk.python.util.api_error import ApiError
try:
products, _ = sdk.python.product.products.fetch()
except ApiError as e:
print(e.message)
print(e.status_code)
print(e.error_code)
else:
for product in products:
print(product.name)
Other Entities Edit
The examples so far have mostly used categories. You may be wondering what other entities exist. A complete list is available in the API reference.
PHP Edit
An SDK is available for PHP
Getting Started Edit
The PHP SDK is available from github.
git clone https://github.com/merchisdk/sdk.git
cd php
Making an Order Edit
The following example shows how to make a web form using the PHP SDK which accepts information from a user about quantity, shipping address, and so on, and which when places an order for a product with Merchi.
The example code requires ‘products.php’ and ‘order_helper.php’, both of
which are distributed with the SDK. You should change the value of
$domain
to reflect the id
of the Merchi store that the order should
be placed with.
<?php
require_once 'products.php';
require_once 'order_helper.php';
$domain = 1; // this should be set to the sales site id
$sitename = "Example Merchi Order Form";
$validates = true;
$resultMsg = '';
$name = '';
$nameErr = '';
$emailAddress = '';
$emailAddressErr = '';
$phoneCode = 'AU';
$phoneCodeErr = '';
$phoneNumber = '';
$phoneNumberErr = '';
$lineOne = '';
$lineOneErr = '';
$lineTwo = '';
$lineTwoErr = '';
$city = '';
$cityErr = '';
$state = '';
$stateErr = '';
$country = '';
$countryErr = '';
$postcode = '';
$postcodeErr = '';
$product = '';
$productErr = '';
$quantity = '';
$quantityErr = '';
$notes = '';
$notesErr = '';
$company = '';
$companyErr = '';
$product_list = get_products_for_domain($domain);
function generate_notes()
{
global $sitename, $product_list, $product, $notes, $quantity;
$result = "order from: $sitename\n";
foreach ($product_list as $a_product) {
if ($a_product->id == $product) {
$result .= "product: $a_product->name\n";
break;
}
}
$result .= "size: example data only\n";
$result .= "colour: example data only\n";
$result .= "ordered qty: $quantity\n";
$result .= "client notes follow: \n$notes\n";
return $result;
}
function transpose($file_post)
{
$file_ary = [];
$file_count = count($file_post['name']);
$file_keys = array_keys($file_post);
for ($i = 0; $i < $file_count; $i++) {
foreach ($file_keys as $key) {
$file_ary[$i][$key] = $file_post[$key][$i];
}
}
return $file_ary;
}
function text_input($label, $id, $value, $err)
{
echo "<div>";
echo "<label for=\"$id\">$label:</label>";
echo "<input type=\"text\" id=\"$id\" name=\"$id\"";
$value = htmlspecialchars($value);
echo " value=\"$value\">";
echo $err;
echo "</div>";
}
function product_select()
{
global $product_list, $product;
echo "<div><label for=\"product\">product:</label>";
echo "<select name=\"product\">";
foreach ($product_list as $a_product) {
$name = htmlspecialchars($a_product->name);
echo "<option value=\"$a_product->id\"";
if ($a_product->id == $product) {
echo ' selected';
}
echo ">$name</option>";
}
echo "</select></div>";
}
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$name = $_POST["name"];
if (empty($name)) {
$nameErr = "name is required";
$validates = false;
}
$emailAddress = $_POST["emailAddress"];
if (empty($emailAddress)) {
$emailAddressErr = "email address is required";
$validates = false;
}
$phoneNumber = $_POST["phoneNumber"];
if (empty($phoneNumber)) {
$phoneNumberErr = "phone number is required";
$validates = false;
}
$lineOne = $_POST["lineOne"];
if (empty($lineOne)) {
$lineOneErr = "line one is required";
$validates = false;
}
$lineTwo = $_POST["lineTwo"];
$city = $_POST["city"];
if (empty($city)) {
$cityErr = "city is required";
$validates = false;
}
$state = $_POST["state"];
$country = $_POST["country"];
if (empty($country)) {
$countryErr = "country is required";
$validates = false;
}
$postcode = $_POST["postcode"];
$product = $_POST["product"];
if (empty($product)) {
$productErr = "product is required";
$validates = false;
}
$quantity = $_POST["quantity"];
if (empty($quantity)) {
$quantityErr = "quantity is required.";
$validates = false;
}
if (!is_numeric($quantity) || $quantity < 1) {
$quantityErr = "please enter a valid quantity";
$validates = false;
}
$quantity = intval($quantity);
$phoneCode = $_POST["phoneCode"];
if (empty($phoneCode)) {
$phoneCodeErr = "phone area code is required";
$validates = false;
}
$notes = $_POST["notes"];
$company = $_POST["company"];
if ($validates) {
try {
place_order($lineOne, $lineTwo, $city, $state, $country,
$postcode, $emailAddress, $phoneCode, $phoneNumber,
$name, $company, $product, $quantity, $domain,
generate_notes(), transpose($_FILES['files']));
$resultMsg = 'order has been placed!';
} catch (Exception $e) {
$msg = htmlspecialchars($e->getMessage());
$resultMsg = 'error from server: ' . $msg;
}
} else {
$resultMsg = 'validation failed';
}
}
?>
<html>
<head>
<title>
Example Merchi Order Form
</title>
<style>
div { margin: 10px; }
</style>
</head>
</body>
<div>
<?php echo $resultMsg ?>
</div>
<div>
<h1>Example Merchi Order Form</h1>
</div>
<form method="post"
action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>"
enctype="multipart/form-data">
<div>
<?php text_input("name", "name", $name, $nameErr) ?>
<?php text_input("email address", "emailAddress", $emailAddress,
$emailAddressErr) ?>
<?php text_input("area code", "phoneCode", $phoneCode,
$phoneCodeErr) ?>
<?php text_input("phone number", "phoneNumber", $phoneNumber,
$phoneNumberErr) ?>
<?php text_input("line one", "lineOne", $lineOne,
$lineOneErr) ?>
<?php text_input("line two", "lineTwo", $lineTwo,
$lineTwoErr) ?>
<?php text_input("city", "city", $city, $cityErr) ?>
<?php text_input("state", "state", $state, $stateErr) ?>
<?php text_input("country", "country", $country, $countryErr) ?>
<?php text_input("postcode", "postcode", $postcode,
$postcodeErr) ?>
<?php product_select() ?>
<?php text_input("quantity", "quantity", $quantity,
$quantityErr) ?>
<?php text_input("notes", "notes", $notes, $notesErr) ?>
<?php text_input("company", "company", $company, $companyErr) ?>
<label>Upload logo or design files:</label><br />
<div id="file-container">
</div>
<a href="#" id="file-add">Upload another</a>
</div>
<div>
<input type="submit" value="place order">
</div>
</form>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js">
</script>
<script>
function add() {
$('#file-container').append('<input name="files[]" type="file"><br />');
}
$('#file-add').on('click', function (e) {
add();
e.preventDefault();
});
add();
</script>
</body>
</html>
Filter Reference Edit
This section documents the list of filters available for reducing or searching list results. For examples of how to actually use the filters, check the individual SDK documentation for your programming language.
Note that the Merchi backend will accept filter names either in mixedCase
or underscore_case
, but they are only listed here in mixedCase
. Typically
you would use whichever one is more idiomatic in your programming language,
for example, the TypeScript SDK request object has property names for each
filter in mixedCase
.
as Edit
The as
filter should be given a user id.
It restricts the result set to only those entities that the specified user would have permission to access (as well as the current user also having access).
tab Edit
The tab
filter should be given a string representing the tab name.
It restricts the result set to entities which would make sense displayed in a seperate UI tab.
The following tab names are available on Notification
entities:
- read
- unread
The following tab names are available on Invoice
entities:
- all (does nothing)
- overdue
- unpaid
The following tab names are available on Job
entities:
- all (does nothing)
- The name of any Category entity
The following tab names are available on Shipment
entities:
- receiving (the user is the receiver)
- sending (the user is the sender)
The following tab names are available on `Usera entities:
- super (only super user admins)
The following tab names are available on Theme
entities:
- public (only publically accessable themes)
state Edit
The state
filter should be given a string representing the state name.
It restricts the result set to entities which are in a specific state. The exact meaning depends on the entity being listed.
The following states are available on the Quote
entity:
- canAddToInvoice
The following states are available on the Assignment
entity:
- assignmentsNeedShipping
- assignmentsAll (does nothing)
The following states are available on the Job
entity:
- jobsActive
- jobsAll (does nothing)
- jobsAllActive
- jobsAllActiveDrafting
- jobsArchived
- jobsCompleted
- jobsUnpaid
- jobsAllWithoutInvoices
- jobsUnassignedProduction
- jobsNeedShipping
- jobsAllShipments
- jobsShipments
- jobsDraftingActiveDesigner
- jobsDraftingUnassignedDesigner
- jobsDraftingDraftsWaitingDesigner
- jobsDraftingDraftsChangesRequestedDesigner
- jobsProductionAllActiveSupplier
- jobsProductionShipmentReady
- jobsProductionShipmentDispatched
- jobsProductionQuotingSupplier
- jobsProductionCompleteSupplier
- jobsActiveProductionSupplier
- jobsProductionShipmentsSupplier
- jobsProductionQuoteSuccessfulSupplier
The following states are available on the Shipment
entity:
- notInvoiced
- notQuoted
- notQuotedOrInvoice
section Edit
The section
filter should be given a number representing the section id.
It is available on Notification
and User
entities.
senderRole Edit
The senderRole
filter should be given either the string system
, or,
anything else. It is available only on Notification
entities. system
means notifications that come form the system itself, rather than another
user.
inDomain Edit
The inDomain
filter should be given a domain id.
It is available on most entity types, and restricts the result set to only those entities belonging to the given domain (store).
inDomainName Edit
The inDomainName
filter should be given a domain name.
It is available on most entity types, and restricts the result set to only those entities belonging to the given domain (store).
It is identical to inDomain
, except that it operates by name rather than
by id. inDomain
and inDomainName
are exclusive.
inDomainRoles Edit
The inDomainRoles
filter should be given a (JSON syntax) list of user
role types (see the role enum in the entity reference for a list).
It is only available on User
entities, and only if either inDomain
or
inDomainName
has also been specified, in which case the users in the
result set are restricted to those which have at least one of the
specified roles/permissions in the specified domain.
publicOnly Edit
The publicOnly
filter should be given a (JSON syntax) boolean.
If true
, the result set is restricted to only those entities which
are shown publically.
It is available on Category
, Product
, SubscriptionPlan
and DomainTag
entities.
isPrivate Edit
The isPrivate
filter should be given a (JSON syntax) boolean.
If true
, the result set is restricted to only those entities which
are marked private.
It is available only on SubscriptionPlan
entities.
entities.
managedOnly Edit
The managedOnly
filter should be given any string, to enable it.
If enabled, the result set is restricted to only those products which the user is a manager of.
It is available only on Product
entities.
entities.
clientOnly Edit
The clientOnly
filter should be given any string, to enable it.
If enabled, the result set is restricted to only those jobs which the user is a client of.
It is available only on Job
entities.
entities.
teamOnly Edit
The trueOnly
filter should be given the string “true”, to enable it.
If enabled, the result set is restricted to only those entities where the user is a team memember (manager, etc.) of the domain of the entity.
It is available on Job
and Domain
entities.
entities.
managedDomainsOnly Edit
The managedDomainsOnly
filter should be given any string, to enable it.
If enabled, the result set is restricted to only those entities where the user is an admin or manager of the domain of the entity.
It is available on Category
, User
, Theme
and Domain
entities.
entities.
businessDomainsOnly Edit
The businessDomainsOnly
filter should be given any string, to enable it.
If enabled, the result set is restricted to only those domains that user is a team member (manager, etc.) of.
It is available only on Domain
entities.
entities.
relatedAssignment Edit
The relatedAssignment
filter should be given an Assignment
id.
It restricts the result set to only those ProductionComments
that are
attached to the specified Assignment
.
It is available only on ProductonComment
entities.
entities.
relatedJob Edit
The relatedJob
filter should be given an Job
id.
It restricts the result set to only those entities which are attached to the specified job,
It is available Notification
, JobComment
, and User
entities.
entities.
relatedProduct Edit
The relatedProduct
filter should be given a Product
id.
It restricts the result set to only those entities which are attached to the specified product.
It is available on ShipmentMethod
, DiscountGroup
, and DomainTag
entities.
jobNotifiable Edit
The jobNotifiable
filter should be given a Job
id.
It restricts the result set to only those User
s which should be
notified about changes to the specified job.
It is available on only the User
entity.
notificationType Edit
The notificationType
filter should be given an integer representing
the notification type (for a complete list, see the enum definition in
the entity reference).
It restricts the result set to only those Notifications
which are of
the specified type.
It is available on only the Notification
entity.
notificationJob Edit
The notificationJob
filter should be given an integer representing
a Job
id.
It restricts the result set to only those Notifications
which are related
to the specified job.
It is available on only the Notification
entity.
notificationRecipient Edit
The notificationRecipient
filter should be given an integer representing
a User
id.
It restricts the result set to only those Notifications
which are directed
to the specified User
.
It is available on only the Notification
entity.
isOrder Edit
The isOrder
filter should be given a (JSON syntax) boolean.
It is available on only the Jobs
entity.
clientId Edit
The clientId
filter should be given an integer representing a User
id.
It restricts the result set to only those entities which have the specified user as a client.
It is available on the Job
, Assignment
, Quote
, and Invoice
entities.
managerId Edit
The managerId
filter should be given an integer representing a User
id.
It restricts the result set to only those entities which have the specified user as a manager.
It is available only on the Invoice
entity.
clientCompanyId Edit
The clientCompanyId
filter should be given an integer representing a
Company
id.
It restricts the result set to only those entities which have the
specified Company
as a client.
It is available on the Shipment
, Job
, Quote
, and Invoice
entities.
senderCompanyId Edit
The senderCompanyId
filter should be given an integer representing a
Company
id.
It restricts the result set to only those entities which have the
specified Company
as the sender.
It is available on the Shipment
and Assignment
entities.
relatedUser Edit
The relatedUser
filter should be given an integer representing a User
id.
It restricts the result set to only those entities which are related
specified User
. The meaning of “related” is worked out in some sensible
way for each type of entity. For example, a User
might be related to
a Job
if they where either the manager, designer, or supplier for it.
It is available on the File
, EnrolledDomain
, Category
, Product
,
Job
, and Company
entities.
dateFrom Edit
The dateFrom
filter should be given a unix timestamp (though, it will
attempt to guess the meaning of other timestamp formats, too)
It restricts the result set to only those entities which occur after the specified timestamp. Usually, the creation date of the entity is meant.
It is available on the Invoice
and Job
entities.
dateTo Edit
The dateTo
filter should be given a unix timestamp (though, it will
attempt to guess the meaning of other timestamp formats, too)
It restricts the result set to only those entities which occur before the specified timestamp. Usually, the creation date of the entity is meant.
It is available on the Invoice
and Job
entities.
categoryId Edit
The categoryId
filter should be given an integer representing a
Category
id.
It restricts the result set to only those products which are in the specified category.
It is available only on the Product
entity.
platformCategoryId Edit
The platformCategoryId
filter should be given an integer representing a
Category
id.
It restricts the result set to only those products which are in the specified platform category.
It is available only on the Product
entity.
companyId Edit
The companyId
filter should be given an integer representing a
Company
id.
It restricts the result set to only those products which are in the specified company.
It is available on the User
, SubscriptionPlan
, Domain
, Shipment
,
Job
, ShipmentMethod
, Invoice
and CountryTax
entities.
componentId Edit
The componentId
filter should be given an integer representing a
Component
id.
It restricts the result set to only those ComponentTag
s which are attached to the specified
Component`
It is available only on the ComponentTag
entity.
name Edit
The name
filter should be given a string.
It restricts the result set to only those entities whose name is as specified.
It is available on the Domain
and Component
entities.
tags Edit
The tags
filter should be given a comma-seperated list of integers, each
representing a tag id.
It restricts the result set to only those entities tagged with the specified tags.
It is available on the Product
, Job
, and Components
entities.
tagNames Edit
The tagNames
filter should be given a comma-seperated list of strings
representing a tag name.
It restricts the result set to only those entities tagged with the specified tags (by name).
It is available only on the Component
entity.
exclude Edit
The exclude
filter should be given a comma-seperated list of integers,
each representing an entity id.
It restricts the result set to only those entities not indicated in the list.
It is available on all entities.
excludeDomains Edit
The excludeDomains
filter should be given a comma-seperated list of
integers, each representing a Domain
id.
It restricts the result set to only those products not in the list of domains.
It is available only on the Product
entity.
includeOnly Edit
The includeOnly
filter should be given a comma-seperated list of
integers, each representing an entity id.
It restricts the result set to only those entities specified in the list, as an alternative to fetching each entity with multiple seperate requests.
It is available on all entities.
domainRoles Edit
The domainRoles
filter should be given a comma-seperated list of
integers, each representing a permission role (see the Entity Reference
enum for a complete list).
Not to be confused with inDomainRoles
, which is a seperate filter.
It restricts the result set to only those domains with which the user is active in one of the specified roles.
It is available only on the Domain
entity.
domainTypes Edit
The domainTypes
filter should be given a comma-seperated list of
integers, each representing a domain type (see the Entity Reference
enum for a complete list).
It restricts the result set to only those domains of one of the given types.
It is available on the Domain
and Theme
entities.
productTypes Edit
The productTypes
filter should be given a comma-seperated list of
integers, each representing a product type (see the Entity Reference
enum for a complete list).
It restricts the result set to only those products of one of the given types.
It is available only on the Product
entity.
memberOnly Edit
The memberOnly
filter should be given a boolean.
It restricts the result set to only those companies of which the user is a member.
It is available only on the Company
entity.
merchiOnly Edit
The merchiOnly
filter should be given a boolean.
If enabled, it restricts the result set to only those entities which are considered platform global.
It is available on the Product
and Category
entities.
inbound Edit
The inbound
filter should be given a boolean.
If enabled, it restricts the result set to only those Invoice
s that the
user is a client (or in a client company) of.
It is available only on the Invoice
entity.
savedByUser Edit
The savedByUser
filter should be given an integer representing a User
id.
It restricts the result set to only those Product
s that the specified
user has “saved”.
It is available only on the Product
entity.
receiverId Edit
The receiverId
filter should be given an integer representing a User
id.
It restricts the result set to only those Shipment
s that the specified
user is the receiver of.
It is available only on the Shipment
entity.
asRole Edit
The asRole
filter should be given an integer representing a permission
role (see the Entity Reference Enum for a complete list).
It restricts the result set to only those EnrolledDomains
s that are of
the specified role.
It is available only on the EnrolledDomain
entity.
Protocol Edit
todo
Authentication Edit
You need to be authenticated for all API requests. You can generate an API key in your developer dashboard.
Add the API key to all requests as a GET parameter.
Nothing will work unless you include this API key
Domain Roles Edit
Each domain user is assigned a domainRole. The domainRole determines which permissions the user has on the domain and it’s associated entities.
Type | Value | Description |
---|---|---|
PUBLIC | 0 | Publice has no permissions on the domain. |
ADMIN | 1 | Admin has all permissions on the domain and it’s associated entities. |
SALES | 2 | Sales has limited permissions on the domain and can add/edit/delete jobs, invoices, products, users and shipments. |
DESIGNER | 3 | Designer can only edit and update job specific attributes related to job drafting and some specific job production attributes. |
SUPPLIER | 4 | Supplier can only edit and update job assignments which they’ve been specifically assigned to. |
CLIENT | 5 | Client can access and edit (some) job attributes where they are the assigned client or in the assigned client company. |
MANAGER | 6 | Manager has limited permissions on the domain and can add/edit/delete jobs, invoices, products, users and shipments. |
ACCOUNTANT | 7 | Accountant can access invoices, jobs and shipments. |
THEME_EDITOR | 8 | Theme editor can create themems, edit them and apply them to the domain. |
Domain Types Edit
Each domain is assigned a domainType. The domainType determines the type of products that can be made and sold by the domain. It can also determines which features are restricted or made available.
Type | Value | Description |
---|---|---|
UNRESTRICTED | 0 | Can create all product types and has access to all features |
SELLER | 1 | Freemium teir domain type can only create: SELLER_MOD and CHAINED_SELLER_MOD product types. This domain type is restricted from updating and customising themes, adding domain team members and selling products on the Merchi marketplace |
SELLER_PLUS | 2 | Can create the following product types: SELLER, SELLER_MOD and CHAINED_SELLER_MOD. This domain type is restricted from selling products on the Merchi marketplace. |
SUPPLIER | 3 | Can create all product types. This domain type can only sell products on the Merchi marketplace by invitation. |
RESTRICTED_SUPPLIER | 4 | Can create all product types. This domain type is restricted from selling products on the Merchi marketplace. |
DOMAIN_SUPPLIER | 5 | Can not create any products. This domain type is created for third party suppliers to allow them to convert their production quotes into invoices and take payments. This domain type can be upgraded to a RESTRICTED_SUPPLIER on subscription. |
Errors Edit
Code | Name | Description |
---|---|---|
200 | OK | Success |
201 | Created | Creation Successful |
400 | Bad Request | We could not process that action |
403 | Forbidden | We couldn’t authenticate you |
All errors will return JSON in the following format:
{
"error": true,
"message": "error message here"
}
Entity Reference Edit
The complete list of merchi entities is available here.