Technical Info

Generic REST API Connector — Implementation Guide

Modified on Mon, 28 Sep at 2:58 PM

TABLE OF CONTENTS


Generic REST API Connector — Implementation Guide

Build an API that SchedEx can connect to. Implement the endpoints and data shapes in this guide and SchedEx read schedule data from your system and write it back — with no custom integration on either side.

Audience: developers implementing the API on the external (host) system. You build: a set of HTTP endpoints. SchedEx provides: a connector that calls them.


Contents


1. Introduction

The Generic REST API Connector is a standard contract for exchanging schedule data between SchedEx and any external scheduling system. By implementing this contract you let SchedEx synchronize projects, activities, dependencies, resources, resource assignments and calendars with your system.

SchedEx calls your API in three ways:

DirectionHTTP verbsWhat SchedEx does
Read from youGETPulls planning objects out of your system.
Write to youPUT (update), POST (create)Pushes planning objects into your system.
Delete from youDELETEConflict handling only — never during a normal transfer.

2. Quick start

What you'll build

A small set of REST endpoints (one group per object type) that speak JSON and follow the conventions in this guide.

Minimum to be functional

At a minimum, implement these read endpoints so SchedEx can pull a schedule:

  1. Test — health/auth check.
  2. Get All Schedules — list selectable schedules.
  3. Get single Schedule — one schedule's detail.
  4. Get Activities, Get Resources, Get Calendars.

Add Activity Links and Resource Assignments to exchange dependencies and resourcing, and the POST/PUT endpoints when you want SchedEx to write back into your system. (See the full required-vs-optional matrix.)

How SchedEx talks to your connector

        SchedEx Data Exchange
               │   (HTTP + JSON, authenticated)
               ▼
            Your API (Generic REST API)
               ├── Schedules (projects)
               ├── Calendars
               ├── Resources
               └── Activities
                    ├── Activity links (dependencies)
                    └── Resource assignments

The order SchedEx calls your endpoints

Reading a schedule into SchedEx

1. Test                  → confirm the API is up and authenticated
2. Get All Schedules     → user picks a schedule
3. Get single Schedule   → fetch its detail
4. Get Calendars
5. Get Resources
6. Get Activities
7. Get Resource Assignments
8. Get Activity Links

Writing a schedule back to your system (calendars and resources first, so activities can reference them):

1. Update Schedule
2. Create/Update Resources
3. Create/Update Calendars
4. Create/Update Activities
5. Create/Update Activity Links
6. Create/Update Resource Assignments

How your system fits — you build a translation layer

You are not redesigning your scheduling system. You add a thin API in front of it that maps your data to the shapes in this guide:

        SchedEx
               │
               ▼
          Your Compliant API
               │
               ▼
   Adapter / translation layer   ← you build this
               │
               ▼
   Your existing scheduling database / engine

Typical implementation effort

Pick the scope that matches your goal:

ScopeImplementGives you
Simple (read-only) connectorTest, Get All Schedules, Get single Schedule, and GET for Activities, Resources, CalendarsSchedEx can import schedules from your system.
Advanced connectorThe above plus Activity Links, Resource Assignments, Custom Fields, and the POST/PUT (and optional DELETE) write-back endpointsFull two-way synchronisation.

Expected outcome

After implementation, a SchedEx admin can register your API as a connector, run a connectivity test, select a schedule, and transfer its data. See Testing your connector.


⚠️ Common implementation requirements

These are the rules most frequently missed during connector development. If something doesn't work, check these first:

  • All id and *Id values are JSON strings ("id": "491", never 491).
  • References use the target object's id — calendarId, resourceId, activityId, predecessorId, successorId all point to an existing object's id.
  • POST (create) returns the newly created id so SchedEx can track the object.
  • List write responses echo each request's rowId unchanged, one entry per row.
  • Pagination is deterministic — sort by internal id and return an accurate totalPages.
  • Dates are ISO-8601 in UTC.
  • Transfers can re-run — match objects by id (and by code if the id changed), and upsert; don't assume every transfer is the first.

3. Glossary

TermMeaning
Schedule (project)A plan: the top-level container for activities, resources and calendars.
ActivityA task in the schedule (work, milestone, summary, etc.).
Activity linkA dependency between two activities (predecessor → successor).
ResourceSomething assigned to do work (people, equipment, material).
Resource assignmentA resource allocated to a specific activity.
CalendarWorking-time definition (working days/hours, holidays) an activity or assignment follows.
Custom fieldExtra, user-defined data on a schedule or activity, defined by a Custom Host Field.
User field setA named group of custom fields; lets some custom fields apply only to certain schedules.
RevisionA version/scope of a schedule (Live, Baseline, Current). Optional.
Planning objectAny of the above exchangeable entities.

4. Core concepts

The data hierarchy

Schedule
 ├─ Calendars
 ├─ Resources ── Resource availabilities
 └─ Activities
     ├─ Activity links  (dependency to another activity)
     └─ Resource assignments (a resource working on this activity)

id and code — the two identifiers

Every planning object has two identifiers:

FieldPurposeRules
idStable system identifier (usually your primary key). SchedEx uses it to track and update objects, and as the target of all references (calendarId, resourceId, …).Always a string. Unique within an object type and schedule. Convert integer/GUID keys to strings.
codeHuman-readable identifier shown to users and used to match objects across systems.A string, unique within the schedule. If your object's name is unique, use it as the code; otherwise use any unique value. If you have no separate code, set code = id.

Why two fields? id is the system identifier SchedEx uses internally to track and update a record; it should never change. code is the business identifier humans recognize and that SchedEx uses to match the same object across systems and in the UI. Keeping them separate lets the displayed code change without breaking the internal links — if you genuinely have only one identifier, set code = id.

Schedule & revision context

Object endpoints are scoped to a schedule, optionally to a revision:

Query parameterRequiredNotes
scheduleIdYes (object endpoints)Which schedule's objects to return. The parameter name is configurable in the connector.
revisionTypeNoSent only when revisions are used. Ignore it if you have no revision concept. See Revision Type.

Not sent to non-schedule endpoints (Test, Get All Schedules, Get Custom Fields).

Custom fields & user field sets

Custom fields are extra key/value data defined by Custom Host Fields. Each is either global (userFieldSetId = null, applies to all schedules) or schedule-specific (userFieldSetId matches the schedule's userFieldSetId). SchedEx scopes custom fields to a schedule by matching userFieldSetId — keep these values consistent between a schedule and its fields.


5. Conventions

  • All id / *Id values are JSON strings — "id": "491", not 491.
  • JSON bodies; Content-Type: application/json.
  • Dates are ISO-8601 — see Dates & time.
  • Unknown fields are ignored — you may return extra fields; SchedEx reads only the documented ones.
  • Property names match case-insensitively; use the exact camelCase names shown.
  • Relative paths — register each endpoint relative to a Base URL; don't return absolute URLs.
  • Shared behaviour (auth, pagination, envelopes, errors) is defined once below and applies to every endpoint.

Versioning & forward compatibility

  • Current ICAC version: 1.0. Report your own API version via the Test ResponseapiVersion field.
  • Future revisions of this contract will be backward-compatible: they may add new optional fields, never remove or repurpose existing ones.
  • Ignore unknown fields you receive, and don't fail if a field you expect is absent — this is what keeps your connector working across versions.

6. Authentication

Choose one scheme when the connector is configured. Every request (including Test) must enforce it.

Authentication typeSupportedHow SchedEx sends it
Service token — Bearer schemeYesAuthorization: Bearer <token>
Service token — custom scheme (e.g. ApiKey)YesAuthorization: <scheme> <token> (scheme configurable)
Azure AD (Microsoft Entra ID)YesAuthorization: Bearer <access-token> obtained from your tenant
Custom headersYesAny additional static headers configured on the connector
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6Il8...
Authorization: ApiKey 5mC343sssa42...

7. Pagination

All list (GET) endpoints are paginated. SchedEx sends:

ParameterTypeMeaning
pageNumberinteger1-based page index.
pageSizeintegerItems per page.

GET /api/activity?scheduleId=SCH-001&pageNumber=3&pageSize=20 → items 41–60.

Return:

{
  "data": [ /* objects for this page */ ],
  "pageNumber": 1,
  "pageSize": 10,
  "totalItems": 50,
  "totalPages": 5
}

Rules

  • Sort consistently (by internal id) so pages neither overlap nor skip.
  • totalPages must be accurate — SchedEx keeps requesting pages until pageNumber > totalPagesor a page returns zero items.
  • Empty results are valid: return 200 with an empty data array.
  • To skip paging entirely, return just { "data": [ … ] } with all items.

8. Status codes & error handling

SituationStatus
Success (read or write, including empty results and partial-batch failures)200
Authentication failed / missing401
Authenticated but not permitted403
Endpoint or resource not found (incl. unknown schedule on Get single Schedule)404
Calendar create/update failed400
Unexpected server error500

Error bodies are surfaced to the user, so return a clear message. Examples:

401 Unauthorized
{
  "message": "Invalid or expired token."
}
404 Not Found
{
  "message": "Schedule 'SCH-999' was not found."
}
400 Bad Request
{
  "message": "Calendar 'C-1' rejected: finish date precedes start date."
}
500 Internal Server Error
{
  "message": "Unexpected error while reading activities. Reference: 8f3a."
}

Even when a batch write partly fails, return 200 and report each item's outcome in the body (next section) — don't fail the whole request.


9. Request & response envelopes

Write request — single object (Update Schedule, Create/Update Calendar)

{
  "scheduleId": "SCH-001",
  "revisionType": 1,
  "...": "…object fields…"
}

Write request — list of objects (activities, links, resources, assignments)

Each item carries a distinct rowId so SchedEx can match the response:

[
  {
    "scheduleId": "SCH-001",
    "revisionType": 1,
    "rowId": 1,
    "id": "123",
    "code": "A100"
  },
  {
    "scheduleId": "SCH-001",
    "revisionType": 1,
    "rowId": 2,
    "id": "124",
    "code": "A101"
  }
]

Write response — single object

{
  "id": "ACT-101",
  "isSuccessful": true,
  "message": "Created successfully"
}

Write response — list (one entry per rowId, even if all failed)

[
  {
    "rowId": 1,
    "id": "ACT-101",
    "isSuccessful": true,
    "message": "Created"
  },
  {
    "rowId": 2,
    "id": "ACT-102",
    "isSuccessful": false,
    "message": "Validation failed: …"
  }
]
FieldTypeMeaning
rowIdintegerThe rowId from the matching request item (list responses only).
idstringThe object's id. On POST (create), return the new id so SchedEx can track it.
isSuccessfulboolWhether this item succeeded.
messagestring (optional)Detail, especially on failure.

Delete request — list

[
  {
    "id": "ACT-101",
    "rowId": 1,
    "scheduleId": "SCH-001",
    "revisionType": 1
  }
]

Respond with the same list envelope (one entry per rowId).


10. Endpoints

Required = needed for SchedEx to work. Optional = implement only if you support that capability. DELETE is conflict-handling only.

ObjectGETPOSTPUTDELETE
TestRequired———
All SchedulesRequired———
Custom FieldsOptional———
ScheduleRequired—Required—
CalendarRequiredRequiredRequired—
ResourceRequiredRequiredRequired—
ActivityRequiredRequiredRequiredOptional
Activity LinkRequiredRequiredRequiredOptional
Resource AssignmentRequiredRequiredRequiredOptional

Read-only systems: if you only want SchedEx to import data from your system, implement the GET endpoints only. POST, PUT and DELETE are required only when you want SchedEx to write back into your system. "Required" above means required for that capability — not that every connector must implement every verb.

Each endpoint below lists its purpose, what SchedEx sends, what you return, and rules.

Test — GET

  • Purpose: lets SchedEx confirm your API is reachable and the credentials are valid (used when an admin tests the connector).
  • Sends: nothing (but enforce auth).
  • Returns: a Test Response.
  • Rules: healthy = success status andisSuccess not false.

Get All Schedules — GET

  • Purpose: lists the schedules a user can choose to synchronise.
  • Sends: pagination only.
  • Returns: paginated Schedule (summary).

Get Custom Fields — GET (optional)

  • Purpose: tells SchedEx which custom fields exist and what object types they apply to.
  • Sends: pagination only.
  • Returns: paginated Custom Host Field.

Get single Schedule — GET

  • Purpose: retrieves one schedule's full detail once a user selects it.
  • Sends:scheduleId (+ optional revisionType). No pagination.
  • Returns:Schedule (detail). Return 404 if not found.

Update Schedule — PUT

  • Purpose: writes schedule-level changes back to your system.
  • Sends:Schedule (write) (single-object envelope).
  • Returns: single-object write response.

Activities — GET / POST / PUT / DELETE

  • Purpose: exchange the tasks of a schedule.
  • GET → paginated Activity (sends scheduleId). POST/PUT → list envelope; return list response (return new ids on POST). DELETE(optional) → conflict handling.
  • Rules: identify each activity by id. If an item has updateOnlyActivityCode: true, update only the code.

Activity Links — GET / POST / PUT / DELETE

  • Purpose: exchange dependencies between activities.
  • GET → paginated Activity Link. POST/PUT → list. DELETE(optional).
  • Rules:predecessorId and successorId must reference activity ids in the same schedule; both are required.

Resources — GET / POST / PUT

  • Purpose: exchange the resources available to a schedule.
  • GET → paginated Resource. POST/PUT → list.

Resource Assignments — GET / POST / PUT / DELETE

  • Purpose: exchange which resource works on which activity.
  • GET → paginated Resource Assignment. POST/PUT → list. DELETE(optional).
  • Rules:resourceId and activityId must reference existing objects.

Calendars — GET / POST / PUT

  • Purpose: exchange working-time definitions.
  • GET → paginated Calendar (with operations). POST/PUT → a single calendar (single-object envelope). Return 400 on failure.

11. Data models

(nullable) = may be null or omitted. All id/*Id fields are strings.

Schedule

Exposed in three shapes — the three operations need different fields.

Schedule (summary)

Returned by Get All Schedules.

PropertyTypeDescription
idstringUnique schedule identifier.
namestringSchedule name (shown as the title in SchedEx).
descriptionstringSchedule description.
startDateDateTime (nullable)Start date.
finishDateDateTime (nullable)Finish date.
userFieldSetIdint (nullable)Custom-field set; null if none.
lastUpdatedDateDateTime (nullable)When last updated.
{
  "id": "SCH-001",
  "name": "Offshore Platform A",
  "description": "EPC schedule for platform A",
  "startDate": "2025-01-01T00:00:00",
  "finishDate": "2026-12-31T00:00:00",
  "userFieldSetId": 2,
  "lastUpdatedDate": "2025-06-01T09:30:00"
}

Schedule (detail)

Returned by Get single Schedule. Uses code as the identifier; carries custom fields.

PropertyTypeDescription
idstringUnique schedule identifier.
codestringHuman-readable identifier (schedule name if unique, else any unique value).
descriptionstringSchedule description.
startDateDateTime (nullable)Start date.
finishDateDateTime (nullable)Finish date.
currentProgressdoubleOverall completion % (0–100).
cutoffDateDateTime (nullable)Data date / cut-off date.
userFieldSetIdint (nullable)Custom-field set; null if none.
customFieldsobjectCustom field values keyed by field name (keys unique).
{
  "id": "SCH-001",
  "code": "P-1001",
  "description": "EPC schedule for platform A",
  "startDate": "2025-01-01T00:00:00",
  "finishDate": "2026-12-31T00:00:00",
  "currentProgress": 12.5,
  "cutoffDate": "2025-06-01T00:00:00",
  "userFieldSetId": 2,
  "customFields": {
    "Phase": "FEED",
    "Discipline": "Structural"
  }
}

Schedule (write)

Sent by Update Schedule — the detail shape plus the envelope. userFieldSetId is read-only and is not sent on write.

PropertyTypeDescription
scheduleIdstringSchedule being updated (envelope).
revisionTypeintegerSee Revision Type.
id, code, description, startDate, finishDate, currentProgress, cutoffDate, customFields—As in Schedule (detail).
{
  "scheduleId": "SCH-001",
  "revisionType": 1,
  "id": "SCH-001",
  "code": "P-1001",
  "description": "EPC schedule for platform A",
  "startDate": "2025-01-01T00:00:00",
  "finishDate": "2026-12-31T00:00:00",
  "currentProgress": 12.5,
  "cutoffDate": "2025-06-01T00:00:00",
  "customFields": {
    "Phase": "FEED",
    "Discipline": "Structural"
  }
}

Activity

PropertyTypeDescription
idstringUnique identifier.
codestringActivity code.
activityTypeintegerSee ActivityType.
descriptionstringDescription.
calendarIdstring (nullable)Calendar this activity follows (a calendar id).
finishAsEarlyAsPossible, startAsEarlyAsPossible, startAsLateAsPossibleboolScheduling constraints.
mustStartOn, mustFinishOn, startNoEarlierThan, startNoLaterThan, finishNoLaterThan, finishOnOrAfterDateTime (nullable)Constraint dates.
actualStart, actualFinishDateTime (nullable)Actual dates.
earlyStart, earlyFinish, lateStart, lateFinishDateTime (nullable)Scheduled dates.
actualWorkHoursdoubleActual work hours completed.
plannedWorkHours, remainingWorkHoursdouble (nullable)Work hours.
durationHours, remainingDurationHoursdouble (nullable)Duration.
freeFloatHours, totalFloatHoursdouble (nullable)Float.
currentProgress, plannedProgressdoubleProgress %.
isAlwaysOnScheduleboolAlways on schedule.
isCancelledbool (nullable)Cancelled.
cancelledDate, frontLineDateDateTime (nullable)Related dates.
customFieldsobjectCustom field values (keys unique).
{
  "id": "2650",
  "code": "A100",
  "activityType": 4,
  "description": "Start Milestone",
  "calendarId": "1674",
  "mustStartOn": "2019-03-01T00:00:00",
  "earlyStart": "2019-03-01T00:00:00",
  "earlyFinish": "2019-03-01T00:00:00",
  "plannedWorkHours": 500.0,
  "remainingWorkHours": 500.0,
  "currentProgress": 0.0,
  "plannedProgress": 100.0,
  "isAlwaysOnSchedule": false,
  "isCancelled": false,
  "durationHours": 0.0
}

A dependency: predecessor → successor.

PropertyTypeDescription
idstringUnique identifier.
codestringLink code.
typeintegerDependency type — SuccessorType.
predecessorIdstringid of the predecessor activity.
successorIdstringid of the successor activity.
lagHoursdouble (nullable)Lag in hours.
calendarIdstring (nullable)Calendar for the lag.
{
  "id": "826",
  "predecessorId": "1150",
  "successorId": "1153",
  "type": 2,
  "lagHours": 48.0,
  "calendarId": "490"
}

Resource

PropertyTypeDescription
idstringUnique identifier.
codestringResource code.
descriptionstringDescription.
resourceAvailabilitiesarray of Resource AvailabilityAvailability windows.

Resource Availability

PropertyTypeDescription
idstringUnique identifier.
codestringCode.
descriptionstringDescription.
startDateTimeDateTime (nullable)Window start.
finishDateTimeDateTime (nullable)Window end.
availableQuantitydouble (nullable)Quantity available.
availableRatedouble (nullable)Rate available.
{
  "id": "331",
  "code": "2|3",
  "description": "RD-0010",
  "resourceAvailabilities": [
    {
      "id": "331-1",
      "startDateTime": "2019-03-01T00:00:00",
      "finishDateTime": "2019-04-01T00:00:00",
      "availableQuantity": 2,
      "availableRate": 0.01
    }
  ]
}

availableQuantity / availableRate / startDateTime / finishDateTime live inside the nested resourceAvailabilities items — not on the resource itself.

Resource Assignment

Connects a resource to an activity.

PropertyTypeDescription
idstringUnique identifier.
codestringAssignment code.
resourceIdstringid of the assigned resource.
activityIdstringid of the activity.
calendarIdstring (nullable)Calendar for the assignment.
resourceUsageTypeintegerSee ResourceUsageType.
plannedHours, actualHours, durationHoursdouble (nullable)Hours.
currentProgressdouble (nullable)Progress %.
earlyStart, earlyFinishDateTime (nullable)Scheduled dates.
lagHoursdouble (nullable)Lag hours.
{
  "id": "3796",
  "code": "2|884|1452",
  "resourceId": "331",
  "activityId": "1150",
  "calendarId": "1",
  "resourceUsageType": 1,
  "plannedHours": 500.0,
  "actualHours": 0.0,
  "currentProgress": 0.0,
  "earlyStart": "2019-03-01T00:00:00",
  "earlyFinish": "2019-04-01T00:00:00",
  "lagHours": 2
}

Calendar

PropertyTypeDescription
idstringUnique identifier.
codestringCalendar code.
descriptionstringDescription.
hoursPerDaydoubleStandard working hours per day.
startDateTimeCalendar start date.
finishDateTimeCalendar end date.
calendarOperationsarray of Calendar OperationWorking-time rules.

Calendar Operation

PropertyTypeDescription
typeintegerSee CalendarOperationType.
weeklyRepeatingPeriodsarrayRecurring weekly working times.
connectedPeriodsarrayOne-off date ranges (e.g. holidays).
  • Weekly repeating period:dayOfWeek (integer, DayOfWeek), startTime (DateTime), finishTime (DateTime). The time-of-day in start/finish defines that day's working hours.
  • Connected period:startDateTime (DateTime), finishDateTime (DateTime).
{
  "id": "491",
  "code": "3|176",
  "description": "5 day, 8 hour",
  "hoursPerDay": 8.0,
  "start": "2016-01-01T00:00:00",
  "finish": "2022-12-31T00:00:00",
  "calendarOperations": [
    {
      "type": 1,
      "weeklyRepeatingPeriods": [
        {
          "dayOfWeek": 1,
          "startTime": "2025-05-22T00:00:00",
          "finishTime": "2025-05-22T08:00:00"
        }
      ],
      "connectedPeriods": []
    },
    {
      "type": 0,
      "weeklyRepeatingPeriods": [],
      "connectedPeriods": [
        {
          "startDateTime": "2019-03-15T00:00:00",
          "finishDateTime": "2019-03-16T00:00:00"
        }
      ]
    }
  ]
}

Custom Host Field

A custom field definition (from Get Custom Fields).

PropertyTypeDescription
idstringUnique identifier.
namestringField name (the custom-field key).
planningObjectTypeintegerObject type it applies to — PlanningObjectType.
dataTypeintegerField data type — TypeCode.
userFieldSetIdint (nullable)Field set; null = global; a value = applies to schedules whose userFieldSetId matches.
aliasstring (nullable)Optional alias.
metadatastring (nullable)Any extra info you want SchedEx to keep.
{
  "id": "R-710D3D4E-80C2-47EE-8756-27B879C3E2A3",
  "name": "Ilap_Term_1",
  "planningObjectType": 2,
  "dataType": 14,
  "userFieldSetId": 2,
  "alias": "",
  "metadata": ""
}

Test Response

PropertyTypeDescription
messagestringStatus message.
isSuccessbool (nullable)Healthy or not. If omitted, a success status is treated as healthy.
apiVersionstringAPI version, e.g. 1.0.0.0.
{
  "message": "Success",
  "isSuccess": true,
  "apiVersion": "1.0.0.0"
}

12. Enumerations

Send the integer value.

ActivityType

ValueName
0NotSet
3RegularActivity
4MilestoneStart
5MilestoneFinish
6Hammock
7TaskDependent
8ResourceDependent
9LevelOfEffort
10WbsSummary

SuccessorType

ValueName
0StartToStart
1StartToFinish
2FinishToStart
3FinishToFinish

ResourceUsageType

ValueName
0NotSet
1Equipment
2StaffTime
3Material

CalendarOperationType

ValueNameMeaning
0RemoveWorkingTimeRemove working time (e.g. holidays).
1AddWorkingTimeAdd working time (e.g. working days, overtime).

DayOfWeek

ValueDay
0Sunday
1Monday
2Tuesday
3Wednesday
4Thursday
5Friday
6Saturday

Revision Type

ValueName
0Live
1OriginalBaseline
2Baseline
3Current

PlanningObjectType

ValueName
1Schedule
2Activity
4Successor
8ResourceUsage
16Resource
32Profile
64Calendar
128Structure

TypeCode

ValueType
3Boolean
9Int32
13Single
14Double
16DateTime
18String

13. Dates & time

  • Format: ISO-8601, e.g. "2025-01-01T00:00:00".
  • Time zone:UTC is strongly recommended for all implementations. The examples carry no offset and SchedEx reads timestamps as given, so returning local time leads to synchronisation problems across vendors and daylight-saving shifts. Use UTC consistently on both reads and writes.
  • Time-of-day matters for calendar working periods (startTime/finishTime define daily hours).
  • Nullable dates: omit the field or send null when there is no value.

14. Performance & data volume

  • Large schedules (10k+ activities) are normal — page your list endpoints and keep totalPages correct.
  • Read batch size and Write batch size are configured on the connector (commonly 1000). SchedEx reads using the page size and writes in batches of that size, so handle array requests/responses efficiently.
  • Avoid timeouts: stream/paginate rather than loading everything into memory; keep per-request work bounded by the batch size.
  • Consistent ordering (by internal id) is essential for correct pagination across large data.

15. Testing your connector

  1. Deploy your API and make it reachable from the SchedEx execution component.
  2. Register the connector in SchedEx with your Base URL, paths and auth (see Section 18).
  3. Test connectivity — SchedEx calls your Test endpoint; confirm it returns success with isSuccess: true.
  4. List schedules — confirm Get All Schedules returns your schedules.
  5. Read a schedule — select one and verify activities, resources, calendars, links and assignments come through.
  6. Write back — run a transfer into your system and confirm the POST/PUT payloads create/update the right objects (check that relationship ids resolve).
  7. Validate the data on both sides matches.

16. Troubleshooting

SymptomLikely causeFix
Objects silently missing after a readNumeric ids, or wrong field namesReturn ids as strings; match the exact field names in this guide.
Pagination loops or drops itemsInaccurate totalPages, or unstable sortCompute totalPages correctly; sort by internal id.
Dependencies don't appearMissing/incorrect predecessorId/successorIdBoth must reference existing activity ids in the schedule.
Resource assignment "orphaned"Missing resourceId or activityIdBoth must reference existing objects.
Activity has no/wrong calendarcalendarId doesn't match a calendar idReference an existing calendar id.
Resource availability ignoredAvailability fields placed flat on the resourceNest them under resourceAvailabilities.
Connectivity test failsAuth not enforced on Test, or wrong scheme/tokenApply auth to every endpoint incl. Test; verify scheme/token.
Custom fields not applied to a scheduleuserFieldSetId mismatchMake field and schedule userFieldSetId consistent (null = global).
Duplicate-key errorsNon-unique id or codeEnsure uniqueness within object type and schedule.
Dates rejected/shiftedNon-ISO format or inconsistent zoneUse ISO-8601; one consistent zone.

17. Certification checklist

Your connector is ready when all of these pass.

Endpoints

  • Test
  • Get All Schedules
  • Get single Schedule
  • Activities (GET, POST, PUT)
  • Resources (GET, POST, PUT)
  • Calendars (GET, POST, PUT)
  • Activity Links (GET, POST, PUT)
  • Resource Assignments (GET, POST, PUT)
  • Custom Fields (if supported)
  • Delete endpoints (if conflict handling needed)

Correctness

  • All id/*Id are strings; id & code unique per schedule.
  • All references resolve (calendarId, resourceId, activityId, predecessorId, successorId).
  • Lists paginated, sorted by id, accurate totalPages.
  • Writes return one result per rowId; POST returns new ids.
  • customFields keys unique; userFieldSetId scoping consistent.
  • Dates ISO-8601; consistent time zone.
  • Auth enforced everywhere incl. Test; health reported via isSuccess.
  • Errors return clear messages with appropriate status codes.

End to end

  • Connectivity test succeeds.
  • A schedule reads in completely.
  • A schedule writes back completely.
  • Read/write data validated on both sides.

18. Registering your API in SchedEx

Pre-requisite: an SchedEx user with the Setup Admin role.

A SchedEx Setup Admin registers your API (Setup → Connectors → New) with:

FieldRequiredWhat it is
TitleYesDisplay name (unique in SchedEx).
Host SystemYesSelect Compliant API.
Execution ComponentYesWhere the transfer runs (Desktop or Autonomous component).
Authentication TypeYesService Token or OAuth2/Azure AD.
Base URLYesRoot URL of your API (e.g. https://example.com/api/v1), no trailing slash.
Test PathYesRelative path of your Test endpoint.
Get All Schedules PathYesRelative path returning schedule summaries.
Get Custom Fields PathNoRelative path for custom field definitions (if supported).
Schedule Id Query ParameterYesThe query-parameter name your API expects for the schedule id (default scheduleId).
Schedule PathYesSingle-schedule GET/PUT.
Calendar PathYesCalendar GET/POST/PUT.
Resource PathYesResource GET/POST/PUT.
Activity PathYesActivity GET/POST/PUT/DELETE.
Activity Link PathYesActivity-link GET/POST/PUT/DELETE.
Resource Assignment PathYesResource-assignment GET/POST/PUT/DELETE.
Read Batch SizeNoPage size when reading (tune for large schedules).
Write Batch SizeYesItems per write request (prevents timeouts).

All paths are relative to the Base URL: Base URL https://example.com/api/v1 + Test Path health → https://example.com/api/v1/health.

Reference implementation & example paths

SchedEx ships a working reference implementation (in a solution called "Analytics"): its GET endpoints return real data filtered by schedule id and revision type, while its POST/PUT/DELETE endpoints return a dummy response — so you can point a connector at it to see the contract in action. Its endpoint paths also make a good naming example:

EndpointExample relative path
Testapi/v3/export/Status
All Schedulesapi/v3/export/Persist/Schedules
Custom Fieldsapi/v3/export/Persist/HostFields
Scheduleapi/v3/export/singleSchedule
Activityapi/v3/export/Activities
Activity Linkapi/v3/export/ActivityLinks
Resourceapi/v3/export/Resources
Resource Assignmentapi/v3/export/ResourceAssignments
Calendarapi/v3/export/Calendars

Sample connector values: Authentication Service Token, Schedule Id Query Parameter reportscheduleid, Read Batch Size 1000, Write Batch Size 1000.


Frequently asked questions

Can I use integers for IDs? No — all id and *Id values must be JSON strings. Convert integer or GUID keys to strings.

Can I omit pagination? Yes. Return the full set as { "data": [ … ] } without the paging fields. For large schedules, paginating is recommended.

Do I need to support revisions? No. If you have no Live/Baseline/Current concept, ignore the revisionType parameter.

Can I build a read-only integration? Yes. Implement the GET endpoints only; add POST/PUT/DELETE later if you want write-back.

Do I have to change my database? No. You build a thin translation layer in front of your existing system (see How your system fits).

What date format and time zone should I use? ISO-8601, in UTC — see Dates & time.

Which endpoints are mandatory? Test, Get All Schedules, Get single Schedule, and GET for Activities, Resources and Calendars. Everything else depends on the capabilities you want (see Endpoints).

What happens if a few items in a batch fail? Return 200 and report each item's outcome by rowId in the response body — don't fail the whole request.

Will new versions break my connector? No, if you ignore unknown fields and tolerate missing optional ones — see Versioning.


Appendix A — A minimal end-to-end example

A tiny schedule with one calendar, one resource, one activity, plus a dependency and an assignment — the shapes SchedEx expects from each endpoint.

GET {Test Path}

{
  "message": "OK",
  "isSuccess": true,
  "apiVersion": "1.0.0.0"
}

GET {Get All Schedules Path}?pageNumber=1&pageSize=10

{
  "data": [
    {
      "id": "SCH-001",
      "name": "Demo Project",
      "description": "Sample",
      "startDate": "2025-01-01T00:00:00",
      "finishDate": "2025-12-31T00:00:00",
      "userFieldSetId": null,
      "lastUpdatedDate": "2025-06-01T09:30:00"
    }
  ],
  "pageNumber": 1,
  "pageSize": 10,
  "totalItems": 1,
  "totalPages": 1
}

GET {Schedule Path}?scheduleId=SCH-001

{
  "id": "SCH-001",
  "code": "Demo Project",
  "description": "Sample",
  "startDate": "2025-01-01T00:00:00",
  "finishDate": "2025-12-31T00:00:00",
  "currentProgress": 0,
  "cutoffDate": null,
  "userFieldSetId": null,
  "customFields": {}
}

GET {Calendar Path}?scheduleId=SCH-001

{
  "data": [
    {
      "id": "CAL-1",
      "code": "Standard",
      "description": "5x8",
      "hoursPerDay": 8.0,
      "start": "2025-01-01T00:00:00",
      "finish": "2025-12-31T00:00:00",
      "calendarOperations": [
        {
          "type": 1,
          "weeklyRepeatingPeriods": [
            {
              "dayOfWeek": 1,
              "startTime": "2025-01-01T08:00:00",
              "finishTime": "2025-01-01T16:00:00"
            }
          ],
          "connectedPeriods": []
        }
      ]
    }
  ],
  "pageNumber": 1,
  "pageSize": 10,
  "totalItems": 1,
  "totalPages": 1
}

GET {Resource Path}?scheduleId=SCH-001

{
  "data": [
    {
      "id": "RES-1",
      "code": "Crane",
      "description": "Mobile crane",
      "resourceAvailabilities": []
    }
  ],
  "pageNumber": 1,
  "pageSize": 10,
  "totalItems": 1,
  "totalPages": 1
}

GET {Activity Path}?scheduleId=SCH-001

{
  "data": [
    {
      "id": "ACT-1",
      "code": "A100",
      "activityType": 3,
      "description": "Pour foundation",
      "calendarId": "CAL-1",
      "currentProgress": 0,
      "plannedProgress": 0,
      "isAlwaysOnSchedule": false,
      "durationHours": 40,
      "customFields": {}
    },
    {
      "id": "ACT-2",
      "code": "A200",
      "activityType": 3,
      "description": "Build walls",
      "calendarId": "CAL-1",
      "currentProgress": 0,
      "plannedProgress": 0,
      "isAlwaysOnSchedule": false,
      "durationHours": 80,
      "customFields": {}
    }
  ],
  "pageNumber": 1,
  "pageSize": 10,
  "totalItems": 2,
  "totalPages": 1
}

GET {Activity Link Path}?scheduleId=SCH-001

{
  "data": [
    {
      "id": "LNK-1",
      "code": "A100->A200",
      "predecessorId": "ACT-1",
      "successorId": "ACT-2",
      "type": 2,
      "lagHours": 0,
      "calendarId": "CAL-1"
    }
  ],
  "pageNumber": 1,
  "pageSize": 10,
  "totalItems": 1,
  "totalPages": 1
}

GET {Resource Assignment Path}?scheduleId=SCH-001

{
  "data": [
    {
      "id": "RA-1",
      "code": "Crane@A200",
      "resourceId": "RES-1",
      "activityId": "ACT-2",
      "calendarId": "CAL-1",
      "resourceUsageType": 1,
      "plannedHours": 80,
      "actualHours": 0,
      "currentProgress": 0
    }
  ],
  "pageNumber": 1,
  "pageSize": 10,
  "totalItems": 1,
  "totalPages": 1
}

Writing back — POST {Activity Path} (request → response)

[
  {
    "scheduleId": "SCH-001",
    "revisionType": 0,
    "rowId": 1,
    "code": "A300",
    "activityType": 3,
    "description": "Roofing",
    "calendarId": "CAL-1"
  }
]
[
  {
    "rowId": 1,
    "id": "ACT-3",
    "isSuccessful": true,
    "message": "Created"
  }
]

Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article