Skip to content
SkyPlanner
  • Product
    • Features
    • Solutions
    • Integrations
  • Services
    • Assisted onboarding services
    • Integration services
    • Customization services
  • Pricing
  • Videos
  • Company
    • About us
    • Contact
    • Become a SkyPlanner partner
  • Docs
  • Get started for free!
  • English

Getting Started

1
  • Getting started with Skyplanner

Resources

40
  • Workstations
    • What is a Workstation?
    • How to add a new Workstation
    • How to edit a Workstation
    • How to delete a Workstation
    • How to add a New Shift to a Workstation
    • How to add a Employee Group to a Workstation
    • What is the Quick Log Mode and how to use it
    • Quick Log Mode Introduction
    • What is a Workstation Exception?
    • How to assign Maintenance to a Workstation
    • How to remove Maintenance from a Workstation
    • How to assign Preventive Maintenance to all Workstations
  • Users
    • How to add a New User
    • Type of User Roles
    • How to edit a User
    • How to delete a User
  • Tools
    • How to add Tools
    • How to assign a Tool to a Workstation
    • How to add Maintenance to a Tool
    • How to inform that a Tool is broken?
    • How to add a Tool to a Product
  • Data Import
    • Using the CSV Import
  • Personnel Registry
    • How to Register Personnel
    • Edit an Employee on the Personnel Registry
    • Delete an Employee from the Personnel Registry
  • Departments
    • How to add a new Department
    • How to edit a department
    • How to delete a Department
  • Customers
    • How to add a New Customer
    • How to edit a Customer
    • How to delete a Customer
    • How to Change the Default Customer Priority
  • Shift Scheduling
    • Shift Scheduling Introduction Video
    • How to add Overtime
    • How to remove Overtime
    • How to change the assigned Person for a Shift on a specific day
  • Personnel Scheduling
    • Personnel Scheduling
  • Default Shifts
    • How to add a Default Shift
    • How to edit a Default Shift
    • How to delete a Default Shift

Gantt Timeline

52
  • Introduction to SkyPlanner’s GANTT Timelime
  • How to move a job to another workstation
  • How to get an Order’s task list.
  • Job Rules
    • How to prohibit changes in an Order 
    • How to add JIT Philosophy in one specific Order
    • How to change the priority to a specific Order
    • How to split Jobs across multiple Workstations
    • Fast Track introduction video
    • Locking a Process Step Job to a Specific Workstation
  • User Interface
    • How to change the color for running jobs in the GANTT Timeline
    • How to see the Job Flow on the GANTT Timeline
    • Turn off Combine overlapping capacities
    • How to highlight Late Jobs
    • How to change the color of a Job Prospect
    • What are Ghost Jobs?
    • How to activate Ghost Jobs in SkyPlanner
    • How to activate Workstation Capacity graph in the GANTT Timeline
    • How to see a Workstation Capacity graph
    • How to activate Show person in running jobs
  • Workstation Rules
    • How to use the Running timelock in one specific workstation
    • Allow moving jobs to other more appropriate workstations
    • How to make a Workstation take a Property into account for scheduling
  • Capacities
    • Capacity on the GANTT Timeline
    • Red Capacity on the GANTT Timeline
    • Blue Capacity on the GANTT Timeline
  • Scheduling
    • How to activate the Automized Reschedule
    • How to Unschedule all my jobs from my GANTT Timeline
    • Unschedule an order item from the GANTT Timeline
    • How to Reschedule only a specific Workstation
  • Workstations and workstation groups
    • How to see a list of a specific Workstation Queue
    • How to show all the Workstations in GANTT Timeline
    • How to hide Workstations in GANTT Timeline
    • How to hide a single Workstation in the GANTT Timeline
    • How to create Workstation Groups
    • What is and how to manage Workstation Efficiencies
    • How to Create a Workstation Group in the GANTT Timeline
    • How to Delete a Workstation Group in the GANTT Timeline
  • Global Rules
    • Running Time Lock
    • How to Change the Default Customer Priority
    • Consider the Materials
    • Consider eligibility dates
    • Dynamic priorities
  • Basic Use
    • How to edit a job in the GANTT Timeline
    • Zoom in and Zoom out
    • Current time on the GANTT Timeline
    • Search function on GANTT Timeline
    • Workstage dependencies
    • What is and how to use the Bulldozer feature
    • Job Details in the GANTT Timeline
    • Jobs on the GANTT Timeline
    • Workstations on the GANTT Timeline
    • Add a quick note to a production process step

Video Guides

33
  • SkyPlanner: The Basics
  • How to start to use your SkyPlanner trial
  • Introduction to SkyPlanner’s GANTT Timelime
  • What is a Workstation?
  • Add Personnel, User Roles and Default Shifts
  • Workstations, Capacities and Maintenance
  • How to add a Process Step
  • Add a new Product to SkyPlanner
  • Subitems and Production Hierarchy
  • Add a Customer
  • Managing Tools in SkyPlanner
  • Adding and managing Materials
  • Create Orders and Order Items
  • How to Unschedule Orders in the GANTT Timeline
  • Running Timelock
  • JIT Manufacturing in SkyPlanner
  • Fast Track introduction video
  • Reduce Lead Time
  • Prioritize Completion Dates
  • How to use Minimum Degree of Manufacturing
  • Job Priorities
  • Managing Customer Priority
  • How to split Jobs across multiple Workstations
  • Managing Leave Times
  • Manage Overtime
  • Using the CSV Import
  • ShopFloorApp and Timer
  • How to create Workstation Groups
  • What is and how to use the Bulldozer feature
  • What is and how to manage Workstation Efficiencies
  • What is the Quick Log Mode and how to use it
  • Add a quick note to a production process step
  • How to calculate your SkyPlanner Pricing

Integrations

9
  • Integration basics
  • Integration tutorial
  • Creating an order
  • Order items
  • Products and materials
  • Scheduled process step timings and workstations
  • Timelogs
  • Workstation/Person exceptions
  • Webhooks

Orders

24
  • How to create a New Order
  • How to edit an Order
  • How to archive an Order
  • How to filter an Order
  • How to update a Prospect into an Order
  • Order Items
    • How to create a New Order Item
    • How to edit an Order Item
    • How to create a Job Prospect 
    • Production Quantity and Ordered Quantity 
    • Process step’s Graph Icon: What is it, and what does it do?
    • Setting and Teardown Times
    • Process Step Completion Degree (Minimum Degree of Manufacture)
    • How to Edit Materials in an Order
    • Add an Attachment to an Order and How to View It in the Timer
  • Purchase Orders
    • What is and how to use the Purchase orders feature
    • How to add a Supplier
    • How to edit a Purchase order
    • How to delete a Purchase order
  • Purchase Order Items
    • How to update the information of a Purchase order item
    • How to delete a Purchase order item
  • Process Steps
    • How to add a New Process Step
    • How to delete a Process Step
    • How to edit a Process Step
  • Assembly Jobs
    • Assembly Jobs (Batch Production / Nesting)

Warehouse

18
  • Warehouse Management
    • How to manage the SkyPlanner’s Warehouse.
    • How to activate a Disabled Product or Material
  • Products
    • How to create a New Product
    • Sub-Products
    • How to update a Product
    • How to deactivate a Product
    • What is Price per Unit?
    • Minimum Production Quantity
    • How to add Material to an existing Product
    • How to add a Property to a Product
    • How to see a Product’s usage history chart?
  • Materials
    • How to add Material to an existing Product
    • How to create a new Material
    • How to edit Material information
    • How to deactivate a material
  • Inventory Transactions
    • How to update a Transaction
    • Inventory Transaction Iconography
    • How to create a Transaction

Timer and Reports

8
  • ShopFloorApp and Timer
  • How to Start a job in the Timer
  • How to Disallow multi logging
  • How to adjust the time on the timer
  • Add an Attachment to an Order and How to View It in the Timer
  • Job report
  • All Timelogs report
  • Order item report

Support

6
  • How to contact Support?
  • How can I get a SkyPlanner Brochure?
  • Can I use SkyPlanner on Mobile version?
  • How to book a meeting with a SkyPlanner specialist
  • How to select your Language in SkyPlanner
  • How to reset your SkyPlanner data?
View Categories
  • Home
  • Docs
  • Integrations
  • Webhooks

Webhooks

Sami
Updated on March 4, 2026

8 min read

This guide explains how to set up your system to receive webhooks from Skyplanner.

Overview #

Skyplanner sends HTTP POST requests to your configured endpoint whenever certain events occur. These webhooks allow your external systems to react in real-time to changes in Skyplanner.

Webhook Events #

Skyplanner can send webhooks for the following events:

JOB_STARTEDA production job has started
JOB_PAUSEDA production job has been paused
JOB_RESUMEDA paused job has been resumed
JOB_COMPLETEDA production job has been completed
PHASER_ORDER_CREATEDA new phaser order was created
PHASER_ORDER_ARCHIVEDA phaser order was archived
PHASER_ORDER_UPDATEDA phaser order was updated
PHASER_ORDER_ROW_CREATEDA new row was added to a phaser order
PHASER_ORDER_ROW_DELETEDA row was deleted from a phaser order
PHASER_ORDER_ROW_UPDATEDA phaser order row was updated
PHASER_JOB_CREATEDA new phaser job was created
PHASER_JOB_DELETEDA phaser job was deleted
PHASER_JOB_UPDATEDA phaser job was updated

Payload Format #

All webhooks are sent as HTTP POST requests with a JSON body:

{
  "event": "Human readable event description",
  "data": {
    // Event-specific data (see examples below)
  },
  "timestamp": 1696262400
}

HTTP Headers #

Every webhook request includes these headers:

HeaderDescription
Content-Typeapplication/json
User-AgentSkyplanner-Webhook/1.0
X-Webhook-SourceSkyplanner
X-Webhook-SignatureHMAC-SHA256 signature (if secret is configured)
X-Webhook-TimestampUnix timestamp when webhook was sent (if secret is configured)

Setting Up Your Receiver #

Requirements #

Your webhook receiver endpoint must:

  1. Accept HTTP POST requests
  2. Be accessible from the internet (or from Skyplanner’s server)
  3. Respond with a 2xx status code to acknowledge receipt
  4. Process requests within 30 seconds (default timeout)
PHP Example #
<?php
// webhook-receiver.php

// Get the raw POST body
$rawPayload = file_get_contents('php://input');

// Get headers
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';

// Your shared secret (same as configured in Skyplanner)
$secret = 'your-webhook-secret-here';

// Verify signature (recommended)
if (!empty($secret) && !empty($signature)) {
    // Check timestamp to prevent replay attacks (5 minute window)
    if (abs(time() - (int)$timestamp) > 300) {
        http_response_code(401);
        exit('Request too old');
    }

    // Verify HMAC signature
    $expectedSignature = hash_hmac('sha256', $rawPayload, $secret);
    if (!hash_equals($expectedSignature, $signature)) {
        http_response_code(401);
        exit('Invalid signature');
    }
}

// Parse the webhook data
$webhook = json_decode($rawPayload, true);

if (json_last_error() !== JSON_ERROR_NONE) {
    http_response_code(400);
    exit('Invalid JSON');
}

// Extract webhook information
$event = $webhook['event'] ?? '';
$data = $webhook['data'] ?? [];
$webhookTimestamp = $webhook['timestamp'] ?? 0;

// Process the webhook based on event type
if (strpos($event, 'Job started') !== false) {
    // Handle job started
    $jobId = $data['production_planning_job_id'] ?? null;
    $phaserJobId = $data['phaser_job_id'] ?? null;
    // ... your logic here
} elseif (strpos($event, 'Phaser Order created') !== false) {
    // Handle order created
    $orderId = $data['id'] ?? null;
    $orderNumber = $data['number'] ?? '';
    // ... your logic here
}

// Log the webhook (optional)
error_log("Received webhook: {$event}");

// Respond with success
http_response_code(200);
echo json_encode(['status' => 'received']);
Node.js Example #
// webhook-receiver.js
const express = require('express');
const crypto = require('crypto');

const app = express();
const SECRET = 'your-webhook-secret-here';

// Parse raw body for signature verification
app.use(express.json({
  verify: (req, res, buf) => {
    req.rawBody = buf.toString();
  }
}));

app.post('/webhooks', (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];

  // Verify signature (recommended)
  if (SECRET && signature) {
    // Check timestamp (5 minute window)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp)) > 300) {
      return res.status(401).json({ error: 'Request too old' });
    }

    // Verify HMAC signature
    const expectedSignature = crypto
      .createHmac('sha256', SECRET)
      .update(req.rawBody)
      .digest('hex');

    if (!crypto.timingSafeEqual(
      Buffer.from(expectedSignature),
      Buffer.from(signature)
    )) {
      return res.status(401).json({ error: 'Invalid signature' });
    }
  }

  // Process the webhook
  const { event, data, timestamp: webhookTimestamp } = req.body;

  console.log(`Received webhook: ${event}`);
  console.log('Data:', JSON.stringify(data, null, 2));

  // Handle different event types
  if (event.includes('Job started')) {
    const { production_planning_job_id, phaser_job_id } = data;
    // ... your logic here
  } else if (event.includes('Phaser Order created')) {
    const { id, number } = data;
    // ... your logic here
  }

  // Acknowledge receipt
  res.status(200).json({ status: 'received' });
});

app.listen(3000, () => {
  console.log('Webhook receiver listening on port 3000');
});
Python example #
# webhook_receiver.py
from flask import Flask, request, jsonify
import hmac
import hashlib
import time

app = Flask(__name__)
SECRET = 'your-webhook-secret-here'

def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool:
    """Verify the webhook signature."""
    if not SECRET or not signature:
        return True  # Skip verification if no secret configured

    # Check timestamp (5 minute window)
    try:
        webhook_time = int(timestamp)
        if abs(time.time() - webhook_time) > 300:
            return False
    except (ValueError, TypeError):
        return False

    # Verify HMAC signature
    expected = hmac.new(
        SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(expected, signature)

@app.route('/webhooks', methods=['POST'])
def receive_webhook():
    # Get raw payload for signature verification
    raw_payload = request.get_data()

    # Get headers
    signature = request.headers.get('X-Webhook-Signature', '')
    timestamp = request.headers.get('X-Webhook-Timestamp', '')

    # Verify signature
    if not verify_signature(raw_payload, signature, timestamp):
        return jsonify({'error': 'Invalid signature'}), 401

    # Parse webhook data
    webhook = request.get_json()
    if not webhook:
        return jsonify({'error': 'Invalid JSON'}), 400

    event = webhook.get('event', '')
    data = webhook.get('data', {})
    webhook_timestamp = webhook.get('timestamp', 0)

    print(f"Received webhook: {event}")
    print(f"Data: {data}")

    # Handle different event types
    if 'Job started' in event:
        job_id = data.get('production_planning_job_id')
        phaser_job_id = data.get('phaser_job_id')
        # ... your logic here
    elif 'Phaser Order created' in event:
        order_id = data.get('id')
        order_number = data.get('number')
        # ... your logic here

    return jsonify({'status': 'received'}), 200

if __name__ == '__main__':
    app.run(port=3000)

Example payloads #

Job Started #
{
  "event": "Job started",
  "data": {
    "id": 45678,
    "person_id": 12,
    "production_planning_job_id": 1234,
    "time": "2024-01-15T08:30:00+00:00",
    "phaser_job_id": 5678,
    "phaser_job_external_id": "EXT-001"
  },
  "timestamp": 1705308600
}
Job Paused #
{
  "event": "Job paused",
  "data": {
    "id": 45679,
    "person_id": 12,
    "production_planning_job_id": 1234,
    "time": "2024-01-15T09:15:00+00:00",
    "phaser_job_id": 5678,
    "phaser_job_external_id": "EXT-001",
    "duration": 2700,
    "amount": 50,
    "faulty_amount": 2,
    "begin_id": 45678
  },
  "timestamp": 1705311300
}
Job Resumed #
{
  "event": "Job resumed",
  "data": {
    "id": 45680,
    "person_id": 12,
    "production_planning_job_id": 1234,
    "time": "2024-01-15T09:45:00+00:00",
    "phaser_job_id": 5678,
    "phaser_job_external_id": "EXT-001"
  },
  "timestamp": 1705313100
}
Job Completed #
{
  "event": "Job completed",
  "data": {
    "id": 45681,
    "person_id": 12,
    "production_planning_job_id": 1234,
    "time": "2024-01-15T10:45:00+00:00",
    "phaser_job_id": 5678,
    "phaser_job_external_id": "EXT-001",
    "duration": 8100,
    "amount": 100,
    "faulty_amount": 3,
    "begin_id": 45678
  },
  "timestamp": 1705316700
}
Phaser Order Created #
{
  "event": "Phaser Order created",
  "data": {
    "order_id": 789,
    "order_number": "ORD-2024-0042",
    "production_planning_customer_id": 15,
    "description": "Customer order for widgets",
    "start_eligibility_date": "2024-01-16T00:00:00+00:00",
    "delivery_date": "2024-01-25T00:00:00+00:00"
  },
  "timestamp": 1705327200
}
Phaser Order Updated #
{
  "event": "Phaser Order updated",
  "data": {
    "order_id": 789,
    "order_number": "ORD-2024-0042",
    "production_planning_customer_id": 15,
    "description": "Updated customer order for widgets",
    "start_eligibility_date": "2024-01-16T00:00:00+00:00",
    "delivery_date": "2024-01-22T00:00:00+00:00"
  },
  "timestamp": 1705332600
}
Phaser Order Archived #
{
  "event": "Phaser Order archived",
  "data": {
    "order_id": 789,
    "order_number": "ORD-2024-0042",
    "production_planning_customer_id": 15,
    "description": "Customer order for widgets",
    "start_eligibility_date": "2024-01-16T00:00:00+00:00",
    "delivery_date": "2024-01-25T00:00:00+00:00"
  },
  "timestamp": 1706256000
}
Phaser Order Row Created #
{
  "event": "Phaser Order row created",
  "data": {
    "phaser_order_row_id": 1234,
    "phaser_order_id": 789,
    "production_planning_product_id": 456,
    "worknumber": "WRK-001",
    "description": "Standard widget assembly",
    "amount": 100,
    "ordered_amount": 100,
    "start_eligibility_date": "2024-01-16T00:00:00+00:00",
    "delivery_date": "2024-01-25T00:00:00+00:00"
  },
  "timestamp": 1705327500
}
Phaser Order Row Updated #
{
  "event": "Phaser Order row updated",
  "data": {
    "phaser_order_row_id": 1234,
    "phaser_order_id": 789,
    "production_planning_product_id": 456,
    "worknumber": "WRK-001",
    "description": "Standard widget assembly",
    "amount": 150,
    "ordered_amount": 150,
    "start_eligibility_date": "2024-01-16T00:00:00+00:00",
    "delivery_date": "2024-01-25T00:00:00+00:00"
  },
  "timestamp": 1705333200
}
Phaser Order Row Deleted #
{
  "event": "Phaser Order row deleted",
  "data": {
    "phaser_order_row_id": 1234,
    "phaser_order_id": 789,
    "production_planning_product_id": 456,
    "worknumber": "WRK-001",
    "description": "Standard widget assembly",
    "amount": 100,
    "ordered_amount": 100,
    "start_eligibility_date": "2024-01-16T00:00:00+00:00",
    "delivery_date": "2024-01-25T00:00:00+00:00"
  },
  "timestamp": 1705334400
}
Phaser Job Created #
{
  "event": "Phaser job created",
  "data": {
    "phaser_job_id": 5678,
    "phaser_order_row_id": 1234,
    "duration": 7200,
    "settingtime": 300,
    "settletime": 0,
    "min_degree": null,
    "workstations": [1, 2, 3],
    "start_eligibility_date": "2024-01-16T00:00:00+00:00"
  },
  "timestamp": 1705328100
}
Phaser Job Updated #
{
  "event": "Phaser job updated",
  "data": {
    "phaser_job_id": 5678,
    "phaser_order_row_id": 1234,
    "duration": 9000,
    "settingtime": 300,
    "settletime": 0,
    "min_degree": null,
    "workstations": [1, 2, 4],
    "start_eligibility_date": "2024-01-17T00:00:00+00:00"
  },
  "timestamp": 1705335000
}
Phaser Job Deleted #
{
  "event": "Phaser job deleted",
  "data": {
    "phaser_job_id": 5678,
    "phaser_order_row_id": 1234,
    "duration": 7200,
    "settingtime": 300,
    "settletime": 0,
    "min_degree": null,
    "workstations": [1, 2, 3],
    "start_eligibility_date": "2024-01-16T00:00:00+00:00"
  },
  "timestamp": 1705338000
}

Data Field Reference #

Job Events (JOB_STARTED, JOB_PAUSED, JOB_RESUMED, JOB_COMPLETED) #
FieldTypeDescription
idintegerTimelog entry ID
person_idintegerID of the person performing the job
production_planning_job_idintegerProduction planning job ID
timestringTimestamp of the event
phaser_job_idintegerPhaser job ID (if available)
phaser_job_external_idstringExternal ID of the phaser job (if available)
durationintegerDuration in seconds (only for paused/completed)
amountfloatQuantity produced (only for paused/completed)
faulty_amountfloatFaulty quantity (only for paused/completed)
begin_idintegerID of the start timelog entry (only for paused/completed)
Phaser Order Events #
FieldTypeDescription
order_idintegerPhaser order ID
order_numberstringOrder number
production_planning_customer_idintegerCustomer ID
descriptionstringOrder description
start_eligibility_datestringEarliest start date
delivery_datestringDelivery deadline
Phaser Order Row Events #
FieldTypeDescription
phaser_order_row_idintegerOrder row ID
phaser_order_idintegerParent order ID
production_planning_product_idintegerProduct ID
worknumberstringWork number identifier
descriptionstringRow description
amountfloatProduced quantity
ordered_amountfloatOrdered quantity
start_eligibility_datestringEarliest start date
delivery_datestringDelivery deadline
Phaser Job Events #
FieldTypeDescription
phaser_job_idintegerPhaser job ID
phaser_order_row_idintegerParent order row ID
durationintegerEstimated duration in seconds
settingtimeintegerSetup time in seconds
settletimeintegerSettle time in seconds
min_degreefloat/nullMinimum degree of manufacture
workstationsarrayList of workstation IDs this job can run on
start_eligibility_datestringEarliest start date

Signature Verification #

Skyplanner signs webhooks using HMAC-SHA256. To verify:

  1. Get the raw request body (before JSON parsing)
  2. Get the `X-Webhook-Signature` header
  3. Calculate `HMAC-SHA256(raw_body, your_secret)`
  4. Compare your calculated signature with the received one using a timing-safe comparison

Important: Always use timing-safe comparison functions (`hash_equals` in PHP, `crypto.timingSafeEqual` in Node.js, `hmac.compare_digest` in Python) to prevent timing attacks.

Replay Attack Prevention #

The ‘X-Webhook-Timestamp’ header contains the Unix timestamp when the webhook was sent. Reject requests older than 5 minutes to prevent replay attacks:

<?php

if (abs(time() - (int)$timestamp) > 300) {
    // Reject: request too old
}

Retry Behavior #

If your endpoint doesn’t respond with a 2xx status code, Skyplanner will retry the webhook:

  • Maximum attempts: 3 (by default)
  • Retry interval: 5 minutes between attempts
  • Timeout: 30 seconds per request

Ensure your endpoint is idempotent, as the same webhook may be delivered multiple times.

Workstation/Person exceptionsIntegration basics
Table of Contents
  • Overview
  • Webhook Events
  • Payload Format
  • HTTP Headers
  • Setting Up Your Receiver
    • Requirements
    • PHP Example
    • Node.js Example
    • Python example
  • Example payloads
    • Job Started
    • Job Paused
    • Job Resumed
    • Job Completed
    • Phaser Order Created
    • Phaser Order Updated
    • Phaser Order Archived
    • Phaser Order Row Created
    • Phaser Order Row Updated
    • Phaser Order Row Deleted
    • Phaser Job Created
    • Phaser Job Updated
    • Phaser Job Deleted
  • Data Field Reference
    • Job Events (JOB_STARTED, JOB_PAUSED, JOB_RESUMED, JOB_COMPLETED)
    • Phaser Order Events
    • Phaser Order Row Events
    • Phaser Job Events
  • Signature Verification
  • Replay Attack Prevention
  • Retry Behavior

Share This Article :

  • Facebook
  • X
  • LinkedIn
  • Pinterest

Was it helpful ?

  • Happy
  • Normal
  • Sad
SkyPlanner logo

Contact sales

Jussi Mäntylä
+358 40 700 0002
[email protected]

Product

Features

Solutions

Become a partner

Privacy policy

TOS

Support

Free trial

Request a demo

Contact sales

Resources

Videos

Powered by Skycode Oy

Rantakatu 2 G (11th floor)
65100 Vaasa, Finland
2204947-0
+358 40 700 0002
skycode.fi

Resources

All ArticlesAPS & SchedulingCareers & SalariesERPManufacturing EfficiencyMES Systems

    • Facebook
    • LinkedIn
    2026 © Skycode Oy
    • logo
    • Home
    • Product
      • Features
      • Solutions
      • Integrations
    • Services
      • Assisted onboarding services
      • Integration services
      • Customization services
    • Pricing
    • Videos
    • Company
      • About us
      • Contact
      • Become a SkyPlanner partner
    • Request a meeting
    • Get started for free!
    • English