Dora API v2

Introduction

Welcome to the Dora API v2 documentation. This API provides programmatic access to Dora's retail pricing and sales functionality.

Authentication

All API requests require authentication using a Bearer token in the Authorization header.

Authorization: Bearer YOUR_ACCESS_TOKEN

Base URL

All API endpoints are relative to:

https://api.configuredora.com/

Making Requests

The API accepts the following HTTP methods:

Responses

All responses are returned in JSON format with appropriate HTTP status codes.

Common status codes:

Authentication Endpoints

Login

Authenticate a user and receive an access token.

POST /auth/login

Request Body

{
    "username": "string",
    "password": "string"
}

Response

// Success (200)
{
    "user_id": number,
    "country_id": number,
    "country_code": "string",
    "country_name": "string",
    "currency_code": "string",
    "dealer_name": "string",
    "role": "string",     // "admin", "extra", "nopurchase", or "dealer"
    "token": "string"     // JWT token valid for 1 hour
}

Get Current User

Retrieve information about the currently authenticated user.

GET /auth/user

Response

// Success (200)
{
    "user_id": number,
    "dealer_name": "string",
    "country_id": number, 
    "country_code": "string",
    "country_name": "string",
    "currency_code": "string",
    "role": "string"      // "admin", "extra", "nopurchase", or "dealer"
}

Reset Password

Request a password reset link via email.

POST /auth/reset_password

Request Body

{
    "username": "string"
}

Response

// Success (200)
{
    "contact": {
        // User contact information
    }
}

// Error (404)
{
    "error": {
        "message": "User not found"
    }
}

Logout

End the current user's session.

POST /auth/logout

Response

{
    "message": "Bye"
}

Authenticate Session

Authenticates the current session and returns a fresh token.

GET /auth/authenticate

Response

// Success (200)
{
    "token": "string"    // Fresh bearer token valid for 1 hour
}

Errors

// Unauthorized (401)
{
    "error": {
        "message": "Not authenticated"
    }
}

Catalog Endpoints

Get Collections

Retrieve available catalog collections for the current user's country.

GET /catalog/collections

Response

// Success (200)
[
    {
        "id": number,          // Collection ID
        "category_name": "string",
        "collection_name": "string",
        "is_new": boolean     // Indicates if this is a new collection
        "image": "string" // Full URL to image
    }
]

// Error (404)
{
    "error": {
        "message": "No collections found"
    }
}

Get Items

Search and retrieve catalog items with pagination and filtering options.

POST /catalog/items

Request Body

{
    "search": "string",      // optional - search by style number
    "page": number,          // optional - default: 1
    "limit": number,         // optional - default: 20, max: 100
    "ids": number | number[], // optional - filter by specific style ID(s)
    "collection_id": number | number[], // optional - filter by collection ID(s)
    "metal_id": number | number[],      // optional - filter by metal ID(s)
    "sort_by": "string",     // optional - "style_no", "style_name", or "style_price"
    "sort_dir": "string",    // optional - "asc" or "desc"
    "show_home": boolean     // optional - filter items shown on home page
}

Response

// Success (200)
{
    "items": [
        {
            "id": number,
            "style_no": "string",
            "information": "string",
            "collection_id": number,
            "category_name": "string",
            "collection_name": "string",
            "metals": [       // Array of metal IDs
                number
            ],
            "width": number,
            "size": number,
            "currency": "string",
            "currency_symbol": "string",
            "price": number,
            "image": "string" // Full URL to image
        }
    ],
    "available_metals": [     // List of all available metals with counts
        {
            "id": number,
            "name": "string",
            "count": number   // Number of items available in this metal
        }
    ],
    "pagination": {
        "total": number,      // Total number of items
        "page": number,       // Current page
        "limit": number,      // Items per page
        "pages": number       // Total number of pages
    }
}

// Error (404)
{
    "error": {
        "message": "No items found"
    }
}

Get Item Details

Retrieve detailed information for a specific catalog item, including available sizes, widths, metals, and diamond specifications.

POST /catalog/item

Request Body

{
    "id": number,           // required - Item ID
    "collection_id": number, // required - Collection ID
    "mode": "string",       // optional - "ring" (default) or "sample" - affects pricing
    "size": number,         // optional - Size in mm
    "width": number,        // optional - Width in mm
    "parts": [              // optional - Parts configuration array
        {
            "name": "string",     // required - Part name
            "metal_id": number,   // optional - Metal ID for this part
            "color": "string",    // optional - Metal color (White/Yellow/Rose)
            "finish": "string"    // optional - Surface finish
        }
    ]
}

Response

// Success (200)
{
    "id": number,              // Style ID
    "style_no": string,        // Style number
    "mode": string,           // Current mode ("ring" or "sample")
    "description": string,     // Style description/text
    "default_size_mm": number, // Default size in millimeters
    "default_width": number,   // Default width
    "default_metal_id": number,// Default metal ID
    "default_weight": string | null, // Client-specific weight category label (e.g. "Light", "Standard", "Heavy") or null if not applicable
    "collection_id": number,   // Collection ID
    "collection_name": string, // Collection name
    "shape": string,          // 3D shape identifier
    "size": number,           // Selected or default size
    "width": number,          // Selected or default width
    "min_width": number,      // Minimum allowed width
    "max_width": number,      // Maximum allowed width
    "country_code": string,   // Country code
    "currency": string,       // Currency code
    "currency_symbol": string,// Currency symbol
    "total_price": number,    // Total price in selected currency
    "parts": [               // Available parts (e.g., "Band", "Setting")
        {
            "name": string,   // Part name
            "available_materials": [
                {
                    "id": number,    // Metal ID
                    "name": string,  // Metal name
                    "code": string,  // Metal code
                    "available_colors": [string], // Available colors: "White", "Yellow", "Rose"
                    "default_color": string | null, // Default color or null
                    "available_finishes": [string], // Available finishes: "Polished", "Hammered", "Brushed", "Iced"
                    "default_finish": string | null, // Default finish or null
                    "weight": number // Weight in grams
                }
            ],
            "default_material_id": number | null, // Default material ID or null
            "selected_material_id": number | null, // Currently selected material ID or null
            "selected_color": string | null,      // Currently selected color or null
            "selected_finish": string | null      // Currently selected finish or null
        }
    ],
    "sizes": [              // Available sizes
        {
            "id": number,   // Size ID
            "size": number, // Size value in country's preferred unit
            "size_mm": number, // Size in millimeters
            "selected": boolean // Whether this size is selected
        }
    ],
    "widths": [            // Available widths
        {
            "width": number, // Width in mm
            "selected": boolean // Whether this width is selected
        }
    ],
    "diamonds": [          // Diamond specifications if applicable
        {
            "cut_code": string,    // Diamond cut code
            "cut": string,         // Diamond cut name
            "count": number,       // Number of diamonds
            "size": number,        // Diamond size
            "total_weight": number,// Total diamond weight
            "vary": number,        // Size variation
            "vary_quantity": number,// Quantity variation
            "black_diamond": boolean,// Whether it's a black diamond
            "quality": string      // Diamond quality name
        }
    ],
    "related_weights": {          // Related styles by weight category
        "lighter": {              // Lighter weight variation (rel_type = 1)
            "id": number,         // Style ID
            "collection_id": number, // Collection ID
            "style_no": string,   // Style number
            "shape": string       // 3D shape identifier
        } | null,                 // null if no lighter variation exists
        "default": {              // Default weight variation (rel_type = 8)
            "id": number,         // Style ID
            "collection_id": number, // Collection ID
            "style_no": string,   // Style number
            "shape": string       // 3D shape identifier
        } | null,                 // null if no default variation exists
        "heavier": {              // Heavier weight variation (rel_type = 2)
            "id": number,         // Style ID
            "collection_id": number, // Collection ID
            "style_no": string,   // Style number
            "shape": string       // 3D shape identifier
        } | null                  // null if no heavier variation exists
    },
    "related_rings": [           // Array of related ring styles (rel_type = 9)
        {
            "id": number,        // Style ID
            "collection_id": number, // Collection ID
            "style_no": string,  // Style number
            "shape": string      // 3D shape identifier
        }
    ]
}

Error Responses

// Error (400) - Missing Required Parameters
{
    "error": {
        "message": "Item ID and Collection ID are required"
    }
}

// Error (400) - Invalid Width
{
    "error": {
        "message": "Width must be between {min} and {max}"
    }
}

// Error (400) - Invalid Size
{
    "error": {
        "message": "Invalid size"
    }
}

// Error (404) - Item Not Found
{
    "error": {
        "message": "Item not found"
    }
}

Notes

  • Both `id` and `collection_id` are required parameters
  • The `mode` parameter can be set to:
    • "ring" (default) - Returns normal retail pricing
    • "sample" - Returns sample pricing (typically lower than retail)
  • The `default_weight` field is client-specific and indicates which weight category (e.g. "Light", "Standard", "Heavy") is considered the default for that client. This field may be null for clients that don't use weight categories.
  • The `parts` parameter allows you to specify custom part configurations with metal, color, and finish selections. The `name` field is required for each part, while `metal_id`, `color`, and `finish` are optional
  • If no selections are provided for a part, the system will use default values from the available materials
  • If `size` is provided, it must match one of the available sizes in the size chart
  • If `width` is provided, it must be between the item's minimum and maximum allowed widths
  • If `size` is not provided, the default size for the country will be used
  • If `width` is not provided, the default width will be used
  • All prices are calculated in the user's country currency
  • The `parts` array contains different components of the item (e.g., "Band", "Setting") with their available materials, colors, and finishes
  • Each material in a part includes:
    • Available colors: "White", "Yellow", "Rose"
    • Available finishes: "Polished", "Hammered", "Brushed", "Iced"
    • Weight in grams
    • Default color and finish (if applicable)
  • Related styles are categorized into two types:
    • Weight variations - Alternative versions of the same style with different weights:
      • lighter (rel_type = 1) - A lighter weight version of the style
      • default (rel_type = 8) - The default weight version of the style
      • heavier (rel_type = 2) - A heavier weight version of the style
    • Related rings (rel_type = 9) - Alternative ring styles that are related to the current item
  • Each related style includes:
    • id - The style ID
    • collection_id - The collection ID the style belongs to
    • style_no - The style number
    • shape - The 3D shape identifier for visualization
  • Weight variations may be null if that particular variation doesn't exist

Get Item PDF

Generate and download a PDF specification sheet for a catalog item.

POST /catalog/pdf

Request Headers

Authorization: Bearer YOUR_ACCESS_TOKEN    // Required - JWT token for authentication

Request Body

{
    "style_id": number,     // required - Item style ID
    "mode": "string",       // optional - "ring" (default) or "sample" - affects pricing
    "size": number,         // optional - Size in mm
    "width": number,        // optional - Width in mm
    "metal_id": number,     // optional - Metal ID
    "image": string,        // optional - Base64 encoded PNG image
    "color": string,        // optional - Metal color (White/Yellow/Rose)
    "finish": string,       // optional - Surface finish
    "engraving_text": string, // optional - Engraving text
    "engraving_font": string  // optional - Engraving font
}

Response

// Success (200)
// Returns PDF file download with Content-Type: application/pdf
// Filename format: style_{style_no}.pdf

// Error (401)
{
    "error": {
        "message": "Not authenticated"
    }
}

// Error (400)
{
    "error": {
        "message": "style_id parameter is required"
    }
}

// Error (404)
{
    "error": {
        "message": "Item not found"
    }
}

Notes

  • Authentication is required to access this endpoint
  • The `mode` parameter can be set to:
    • "ring" (default) - Returns normal retail pricing in the PDF
    • "sample" - Returns sample pricing (typically lower than retail) in the PDF
  • The PDF includes:
    • Item style number as title
    • Item image (either provided base64 image or stored image)
    • Item specifications:
      • Material (metal name)
      • Color (if provided)
      • Finish (if provided)
      • Size in mm
      • Width in mm
      • Engraving details (if provided):
        • Engraving text
        • Engraving font
      • Price in user's currency (if available)
    • Item description (if available)
  • The PDF is formatted with:
    • Two-column layout for image and specifications
    • 15mm margins on all sides
    • No headers or footers
    • UTF-8 encoding support
    • Dealer name as author
    • System name as creator
  • If no image is provided in the request, the system will attempt to use the stored image for the style
  • The response is a direct file download with appropriate headers for PDF content type
  • All prices are calculated in the user's country currency
  • The PDF is generated using TCPDF library

Cart Endpoints

Get Cart

Retrieve the current user's shopping cart.

GET /cart

Response

// Success (200)
{
    "items": [
        {
            "type": "ring",
            "id": number,
            "quantity": number,
            "price": number,
            "item_key": "string",
            "options": {
                "size": number,
                "width": number,
                "parts": [          // Parts configuration array
                    {
                        "name": "string",     // Part name (e.g., "Band", "Setting")
                        "metal_id": number,   // Metal ID for this part
                        "color": "string",    // Metal color (White/Yellow/Rose)
                        "finish": "string",    // Surface finish (Polished/Hammered/Brushed/Iced)
                        "metal_name": "string"  
                    }
                ],
                "diamonds": [] // optional
            },
            "details": {
                "style_no": "string",
                "description": "string",
                "default_size_mm": number,
                "default_width": number,
                "min_width": number,
                "max_width": number,
                "size_table": "string",
                "local_size": number,
                "image": "string" // Base64 encoded image data (data:image/png;base64,...)
            }
        }
    ],
    "total": number
}

Notes

  • The `parts` array contains the configuration for each part of the ring (e.g., "Band", "Setting"), including metal, color, and finish selections
  • Each part includes:
    • `name` - The part name
    • `metal_id` - The metal ID selected for this part
    • `color` - Metal color: "White", "Yellow", or "Rose"
    • `finish` - Surface finish: "Polished", "Hammered", "Brushed", or "Iced"
  • The image field in the response contains a base64 encoded PNG image with the data URL prefix (data:image/png;base64,...)
  • Images are resized to a maximum dimension of 400px while maintaining aspect ratio
  • For rings, the image may be either a custom uploaded image or the default style image

Update Cart

Add or update items in the shopping cart. When adding items, if an identical configuration already exists, the quantities will be combined.

PUT /cart

Request Body - Update Existing Item

{
    "item_key": "string",    // Required - Unique identifier of existing cart item
    "quantity": number       // Required - Quantity to add/subtract (will be added to existing quantity)
}

Request Body - Add Ring

{
    "type": "ring",
    "id": number,           // Required - Item ID
    "quantity": number,     // Required - Quantity to add (minimum 1)
    "image": "string",      // Optional - Base64 encoded PNG image (data:image/png;base64,...)
    "options": {
        "size": number,     // Required - Size in mm
        "width": number,    // Required - Width in mm
        "parts": [          // Required - Parts configuration array
            {
                "name": "string",     // Required - Part name (e.g., "Band", "Setting")
                "metal_id": number,   // Optional - Metal ID for this part
                "color": "string",    // Optional - Metal color (White/Yellow/Rose)
                "finish": "string"    // Optional - Surface finish (Polished/Hammered/Brushed/Iced)
            }
        ],
        "diamonds": [       // Optional - diamond configurations
            {
                "diamond_cut_id": number, // Required - Diamond cut ID
                "diamond_count_size": number, // Required - Diamond count size
                "diamond_size": number, // Required - Diamond size
                "diamond_quality_id": string // Required - Diamond quality ID
            }
        ]
    }
}

Request Body - Add Product

{
    "type": "product",
    "id": number,          // Product ID
    "quantity": number     // Quantity to add (minimum 1)
}

Response

// Success (200)
// Empty response with 200 status code

// Error (400) - Invalid Request Format
{
    "error": "Invalid request format"
}

// Error (400) - Missing Parameters
{
    "error": "Missing required parameters" | "Missing required ring options" | 
             "Quantity is required" | "Invalid item type" | "Part name is required" |
             "Missing required ring size or width" | "Missing required ring options or invalid values"
}

// Error (400) - Invalid Image
{
    "error": "Invalid image format. Only base64 encoded PNG images are supported." | 
             "Invalid base64 image data"
}

// Error (404) - Item Not Found
{
    "error": "Item not found or incorrect options" | "Product not found"
}

// Error (500) - Server Error
{
    "error": "Failed to save cart"
}

Notes

  • For rings, all required options (parts, size, width) must be provided
  • The `parts` array is required and must contain at least one part with a `name` field
  • Each part in the `parts` array can specify:
    • `name` (required) - The part name (e.g., "Band", "Setting")
    • `metal_id` (optional) - The metal ID for this specific part
    • `color` (optional) - Metal color: "White", "Yellow", or "Rose"
    • `finish` (optional) - Surface finish: "Polished", "Hammered", "Brushed", or "Iced"
  • For multi-part rings (e.g., band + setting), each part can have different metal, color, and finish selections
  • The diamonds array is optional for rings
  • The image parameter is optional for rings and must be a base64 encoded PNG image with the proper data URL prefix (data:image/png;base64,...)
  • Products only require id and quantity
  • Quantity must be at least 1 for both types
  • If an identical item configuration exists (including parts), quantities will be combined
  • Each item gets a unique item_key generated based on its configuration (including parts)
  • If an image is provided for a ring, it will be stored with the cart item and used instead of the default style image

Remove from Cart

Remove an item from the shopping cart.

DELETE /cart

Request Body

{
    "item_key": "string"    // Unique identifier of cart item to remove
}

Response

// Success (200)
// Empty response with 200 status code

// Error (400)
{
    "error": "Item key required"
}

// Error (404)
{
    "error": "Cart not found" | "Item not found in cart"
}

// Error (500)
{
    "error": "Failed to save cart"
}

Purchase Cart

Convert the current cart into a sales order.

POST /cart

Request Body

// Empty request body - uses current cart contents

Response

// Success (200)
{
    "orderNo": "string",    // Generated order number
    "total": number        // Total order amount
}

// Error (400)
{
    "error": "Cart is empty"
}

// Error (404)
{
    "error": "Cart not found"
}

// Error (500)
{
    "error": "Failed to create order"
}

Notes

  • Creates a sales order from the current cart contents
  • Sends confirmation emails to both the customer and sales office
  • Order confirmation includes:
    • Order reference number
    • Order date
    • Dealer information
    • Detailed item specifications (style numbers, sizes, metals, etc.)
    • Diamond information (if applicable)
    • Pricing details
  • Cart must contain at least one item
  • User must be authenticated and have purchase permissions

Directus Endpoints

Get Directus Collections

Retrieve collections from the Directus CMS.

POST /directus/collections

Request Body

{
    "search": "string"    // optional - Search term to filter collections
}

Response

// Success (200)
[
    {
        "id": number,
        "country_id": number,
        "country_name": "string",
        "collection_name": "string"    // Format: "{country_name} - {collection_name}"
    }
]

// Error (404)
{
    "error": {
        "message": "No collections found"
    }
}

Product Endpoints

Get Products

Search and retrieve products with pagination and sorting options. Products are filtered by the current user's country.

POST /product/items

Request Body

{
    "search": "string",      // optional - search term for name or description
    "page": number,          // optional - default: 1
    "limit": number,         // optional - default: 20, max: 100
    "sort_by": "string",     // optional - "product_name" or "product_price"
    "sort_dir": "string"     // optional - "asc" or "desc"
}

Response

// Success (200)
{
    "items": [
        {
            "id": number,
            "name": "string",
            "description": "string",
            "price": number,
            "image": "string"  // Full URL to product image
        }
    ],
    "pagination": {
        "total": number,      // Total number of items
        "page": number,       // Current page
        "limit": number,      // Items per page
        "pages": number       // Total number of pages
    }
}

// Error (404)
{
    "error": {
        "message": "No items found"
    }
}

Get Product Details

Retrieve detailed information for a specific product.

GET /product/item/{id}

Parameters

id: number    // Required - Product ID

Response

// Success (200)
{
    "id": number,
    "name": "string",
    "description": "string",
    "price": number,
    "image": "string"  // Full URL to product image
}

// Error (400)
{
    "error": {
        "message": "Item ID is required"
    }
}

// Error (404)
{
    "error": {
        "message": "Item not found"
    }
}

Submit Product Request

Submit a customized product request form with dimensions and optional shipping details.

POST /product/request

Request Body

{
    "name": "string",         // Required - Product name
    "width": number,         // Required - Product width
    "height": number,        // Required - Product height
    "logo": File,           // Optional - Company logo file (multipart/form-data)
    "store_name": "string", // Optional - Store name
    "same_address": boolean,// Optional - Use same address flag
    "streetname": "string", // Required if same_address is false - Street address
    "city": "string",      // Required if same_address is false - City
    "country": "string",   // Required if same_address is false - Country
    "zipcode": "string",   // Required if same_address is false - Zip/postal code
    "notes": "string",     // Optional - Additional notes
    "terms": boolean       // Required - Must be true to accept terms
}

Response

// Success (200)
{
    "success": {
        "message": "Request submitted successfully"
    }
}

// Error (400) - Missing Required Fields
{
    "error": {
        "message": "Missing required fields"
    }
}

// Error (400) - Invalid Address
{
    "error": {
        "message": "Invalid address fields"
    }
}

// Error (500) - Email Send Failure
{
    "error": {
        "message": "Failed to send request: [error details]"
    }
}

Notes

  • Authentication is required to access this endpoint
  • Required fields:
    • name - Product name
    • width - Product width
    • height - Product height
    • terms - Must be true to accept terms
  • If same_address is false, all address fields are required and must follow these validation rules:
    • streetname: alphanumeric characters and spaces only
    • city: alphabetic characters and spaces only
    • country: alphabetic characters and spaces only
    • zipcode: numeric characters only
  • The logo file should be submitted as multipart/form-data
  • On successful submission, an email will be sent to the configured product request email address with all provided details
  • The email will include:
    • Product name and dimensions
    • Store name (if provided)
    • Shipping address (if provided)
    • Additional notes (if provided)
    • Logo attachment (if provided)

Contact Endpoints

Submit Contact Form

Submit a contact form message. This endpoint requires authentication using a JWT token.

POST /contact/submit
Authorization: Bearer YOUR_ACCESS_TOKEN

Request Headers

Authorization: Bearer YOUR_ACCESS_TOKEN    // Required - JWT token for authentication

Request Body

{
    "name": "string",     // Required - Contact name
    "email": "string",    // Required - Contact email
    "comment": "string"   // Required - Message content
}

Response

// Success (200)
{
    "success": {
        "message": "Message sent successfully"
    }
}

// Error (400) - Missing Required Fields
{
    "error": {
        "message": "Missing required fields"
    }
}

// Error (400) - Invalid Email
{
    "error": {
        "message": "Invalid email format"
    }
}

// Error (500) - Email Send Failure
{
    "error": {
        "message": "Failed to send message: [error details]"
    }
}

Notes

  • This endpoint requires authentication using a valid JWT token in the Authorization header
  • Required fields:
    • name - Contact name
    • email - Valid email address
    • comment - Message content
  • On successful submission:
    • An email is sent to the configured recipient
    • The email includes the contact name, email, and message
    • The message is formatted in HTML with proper escaping of special characters
  • The email is sent using SMTP with UTF-8 encoding
  • Authentication errors will return a 401 status code with an appropriate error message