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 Users 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 ComponentTags 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 Invoices 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 Products 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 Shipments 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 EnrolledDomainss 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.