TypeScript SDK for the ShineOn fulfillment API. Zero runtime dependencies, CJS/ESM dual build, Node 18+.
npm install @sellersmith/shineon-sdkimport { ShineOn } from '@sellersmith/shineon-sdk';
const client = new ShineOn({ token: process.env.SHINEON_API_TOKEN! });
// Create an order (V1)
const { order } = await client.orders.create({
order: {
source_id: 'store-order-1001',
shipment_notification_url: 'https://yourstore.com/webhooks/shineon',
shipping_method: 'standard-us',
shipping_address: {
name: 'Jane Smith',
address1: '123 Main St',
city: 'Austin',
zip: '78701',
country_code: 'US',
},
line_items: [
{
store_line_item_id: 'item-1',
sku: 'SNO-NECKLACE-GOLD',
quantity: 1,
properties: { 'Engraving Line 1': 'Always & Forever' },
},
],
},
});
console.log(order.id, order.status); // 98765 'awaiting_payment'const client = new ShineOn({
token: 'your-api-token', // required
baseUrl: 'https://api.shineon.com', // optional, default shown
timeout: 30_000, // optional, ms (default 30 000)
maxRetries: 3, // optional, 429 retry attempts (default 3)
});| Option | Type | Default | Description |
|---|---|---|---|
token |
string |
— | API access token (required) |
baseUrl |
string |
https://api.shineon.com |
Base URL override |
timeout |
number |
30000 |
Request timeout in milliseconds |
maxRetries |
number |
3 |
Max retry attempts for rate-limited (429) requests |
client.orders.create(params) // POST /v1/orders
client.orders.createV2(params) // POST /v2/orders
client.orders.list(params?) // GET /v1/orders
client.orders.get(id) // GET /v1/orders/{id}
client.orders.update(id, params) // PUT /v1/orders/{id}
client.orders.hold(id) // POST /v1/orders/{id}/hold
client.orders.ready(id) // POST /v1/orders/{id}/ready
client.orders.cancel(id) // POST /v1/orders/{id}/cancel| Method | Params | Returns |
|---|---|---|
create(params) |
CreateOrderV1Params |
Promise<OrderResponse> |
createV2(params) |
CreateOrderV2Params |
Promise<OrderResponse> |
list(params?) |
ListOrdersParams (optional) |
Promise<OrderListResponse> |
get(id) |
number | string |
Promise<OrderResponse> |
update(id, params) |
number | string, UpdateOrderParams |
Promise<OrderResponse> |
hold(id) |
number | string |
Promise<OrderResponse> |
ready(id) |
number | string |
Promise<OrderResponse> |
cancel(id) |
number | string |
Promise<void> (202 Accepted) |
ListOrdersParams — all fields optional:
| Field | Type | Description |
|---|---|---|
ids |
string |
Comma-separated order IDs |
source_ids |
string |
Comma-separated source IDs |
source_po_numbers |
string |
Comma-separated source PO numbers |
status |
OrderStatus |
Filter by status |
created_at_min |
string |
ISO 8601 datetime |
created_at_max |
string |
ISO 8601 datetime |
updated_at_min |
string |
ISO 8601 datetime |
updated_at_max |
string |
ISO 8601 datetime |
page |
number |
Page number |
limit |
number |
Max 250, default 50 |
client.skus.list() // GET /v1/skus
client.skus.get(skuId) // GET /v1/skus/{skuId}| Method | Params | Returns |
|---|---|---|
list() |
— | Promise<SkuListResponse> |
get(skuId) |
string |
Promise<SkuResponse> |
SKU properties by type:
| SKU type | buyer_uploads |
engravings |
size_option |
Notes |
|---|---|---|---|---|
| artwork | >0 |
— | — | Requires print_url in order properties |
| engraving | — | 1 or 2 |
— | Requires engraving line properties |
| ring | — | optional | true |
Requires Size (US) property |
| standard | — | — | — | No customization required |
client.productTemplates.list(params?) // GET /v1/product_templates
client.productTemplates.listV2(params?) // GET /v2/product_templates
client.productTemplates.get(id) // GET /v1/product_templates/{id}| Method | Params | Returns |
|---|---|---|
list(params?) |
ListProductTemplatesV1Params (optional) |
Promise<ProductTemplateListResponse> |
listV2(params?) |
ListProductTemplatesV2Params (optional) |
Promise<ProductTemplateListResponse> |
get(id) |
number | string |
Promise<ProductTemplateResponse> |
ListProductTemplatesV1Params: page?, per_page? (default 15)
ListProductTemplatesV2Params: page?, per_page?, search? (adds full-text search)
Both list methods return ProductTemplateListResponse — a paginated response with data, links, and meta fields.
client.renders.get(id) // GET /v1/renders/{id}
client.renders.make(id, params) // POST /v1/renders/{id}/make| Method | Params | Returns |
|---|---|---|
get(id) |
number | string |
Promise<RenderResponse> |
make(id, params) |
number | string, MakeRenderParams |
Promise<RenderResponse> |
MakeRenderParams — provide exactly one image source:
| Field | Type | Description |
|---|---|---|
src |
string |
Source image URL (mutually exclusive with attachment/random) |
attachment |
string |
Base64-encoded source image (mutually exclusive with src/random) |
random |
number |
Set to 1 to use a random sample image |
output_width |
number |
Output width in pixels |
output_format |
string |
Output format: 'png', 'jpg' |
output_quality |
number |
Quality 1–100 (for lossy formats) |
The key difference is how personalizations are represented on order line items.
V1 uses a flat properties object with named keys:
line_items: [{
store_line_item_id: 'item-1',
sku: 'SNO-NECKLACE-GOLD',
quantity: 1,
properties: {
'Engraving Line 1': 'Always & Forever',
engraving_font: 'Script', // slug alias also accepted
},
}]V2 uses a personalizations array of key/value pairs:
line_items: [{
store_line_item_id: 'item-1',
sku: 'SNO-NECKLACE-GOLD',
quantity: 1,
personalizations: [
{ key: 'engraving_line_1', value: 'Always & Forever' },
{ key: 'engraving_font', value: 'Script' },
],
}]V2 product templates (listV2) include a personalizations array that describes each accepted key, its type (text, image_url, svg_url, choice), and validations — use this to discover valid keys before creating an order.
on_hold ──ready()──> awaiting_payment ──(auto)──> in_production ──(auto)──> shipped
^ |
└───────hold()─────────────┘
Any non-shipped status ──cancel()──> cancelled
| Status | Description |
|---|---|
on_hold |
Order created with ready: 0 or put on hold manually |
awaiting_payment |
Order accepted and waiting for production slot |
in_production |
Order is being manufactured |
shipped |
Order has shipped; tracking info available on line items |
cancelled |
Order cancelled; cancel() returns 202 Accepted |
update() is only permitted when status is on_hold or awaiting_payment.
| Value | Description |
|---|---|
standard-us |
Standard US domestic shipping |
international |
International shipping |
| (custom) | Additional methods available in your partner account |
The type is 'standard-us' \| 'international' \| string — any string accepted by your ShineOn partner account is valid.
All API errors throw a ShineOnError:
import { ShineOn, ShineOnError } from '@sellersmith/shineon-sdk';
try {
const { order } = await client.orders.get(99999);
} catch (err) {
if (err instanceof ShineOnError) {
console.error(err.message); // e.g. "Order not found"
console.error(err.status); // HTTP status: 404
console.error(err.responseBody); // raw parsed response body
}
}status |
Cause |
|---|---|
400 |
Validation error — check responseBody.error for details |
401 |
Invalid or missing API token |
404 |
Resource not found |
422 |
Unprocessable entity |
429 |
Rate limit hit — SDK auto-retries up to maxRetries times |
408 |
Request timed out (client-side) |
0 |
Network error or unknown failure |
When the API returns 429 Too Many Requests, the SDK automatically retries with exponential backoff:
- Delay uses the
Retry-Afterresponse header if present - Otherwise:
min(1000 * 2^attempt, 30_000)ms - Retries up to
maxRetriestimes (default 3) - After exhausting retries, throws
ShineOnErrorwithstatus: 429
Set shipment_notification_url on each order. ShineOn will POST a ShipmentNotification payload to that URL whenever fulfillment status changes.
import type { ShipmentNotification } from '@sellersmith/shineon-sdk';
// Express route handler
app.post('/webhooks/shineon', (req, res) => {
const payload = req.body as ShipmentNotification;
for (const item of payload.order.line_items) {
console.log(
`Item ${item.store_line_item_id} shipped via ${item.tracking_company}: ${item.tracking_number}`
);
}
res.sendStatus(200);
});ShipmentNotification shape:
{
order: {
id: number;
source_id: string;
store_order_id: string;
line_items: Array<{
id: number;
store_line_item_id: string;
sku: string;
quantity: number;
tracking_company: string;
tracking_number: string;
}>;
};
}All types are exported from the package root:
import type {
ShineOnConfig,
CreateOrderV1Params,
CreateOrderV2Params,
UpdateOrderParams,
ListOrdersParams,
OrderResponse,
OrderListResponse,
Order,
OrderStatus,
ShippingMethod,
ShippingAddress,
LineItemProperties,
Personalization,
SkuResponse,
SkuListResponse,
Sku,
ProductTemplateResponse,
ProductTemplateListResponse,
ProductTemplate,
TemplatePersonalization,
RenderResponse,
MakeRenderParams,
Render,
ShipmentNotification,
} from '@sellersmith/shineon-sdk';MIT — see LICENSE.