API Endpoints

Every API request needs an OAuth 2.0 access token.

In the API, a Hole is called a fairway. This page uses fairway only for field names.

Base URL: https://parkdly.com/api/v1

Authentication

Include your access token in the Authorization header:

Authorization: Bearer {access_token}

Courses

List User's Courses

Returns all courses that are linked to your app for the authenticated user.

GET /api/v1/courses

Response:

{
  "courses": [
    {
      "id": "course_123",
      "externalCourseId": "your-app-course-id",
      "name": "Example DGC",
      "location": {
        "lat": 60.1699,
        "lng": 24.9384
      },
      "studioUrl": "/studio/destinations/dest_456/courses/course_123",
      "fairways": [
        {
          "id": "fairway_1",
          "number": 1,
          "par": 3,
          "distance": 100,
          "teePosition": {
            "lat": 60.1699,
            "lng": 24.9384
          },
          "targetPosition": {
            "lat": 60.17,
            "lng": 24.94
          },
          "flightPath": [
            {
              "order": 0,
              "lat": 60.1699,
              "lng": 24.9384
            },
            {
              "order": 1,
              "lat": 60.16995,
              "lng": 24.9392
            },
            {
              "order": 2,
              "lat": 60.17,
              "lng": 24.94
            }
          ]
        }
      ],
      "createdAt": "2025-01-15T10:00:00Z",
      "updatedAt": "2025-01-15T12:00:00Z"
    }
  ],
  "total": 1
}

Get Course Details

Returns the details of one course that is linked to your app.

GET /api/v1/courses/{courseId}

Response:

{
  "id": "course_123",
  "externalCourseId": "your-app-course-id",
  "name": "Example DGC",
  "location": {
    "lat": 60.1699,
    "lng": 24.9384
  },
  "studioUrl": "/studio/destinations/dest_456/courses/course_123",
  "fairways": [
    {
      "id": "fairway_1",
      "number": 1,
      "par": 3,
      "distance": 100,
      "teePosition": {
        "lat": 60.1699,
        "lng": 24.9384
      },
      "targetPosition": {
        "lat": 60.17,
        "lng": 24.94
      },
      "flightPath": [
        {
          "order": 0,
          "lat": 60.1699,
          "lng": 24.9384
        },
        {
          "order": 1,
          "lat": 60.16995,
          "lng": 24.9392
        },
        {
          "order": 2,
          "lat": 60.17,
          "lng": 24.94
        }
      ]
    },
    {
      "id": "fairway_2",
      "number": 2,
      "par": 4,
      "distance": 150,
      "teePosition": {
        "lat": 60.1701,
        "lng": 24.9386
      },
      "targetPosition": {
        "lat": 60.1702,
        "lng": 24.9402
      },
      "flightPath": null
    }
  ],
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T12:00:00Z"
}

Create Course

Creates a course and links it to your app. You can include the course location and fairway data with Tee and Target positions.

POST /api/v1/courses

Request Body:

{
  "externalCourseId": "your-app-course-id",
  "name": "New Course Name",
  "location": {
    "lat": 60.1699,
    "lng": 24.9384
  },
  "fairways": [
    {
      "number": 1,
      "teePosition": {
        "lat": 60.1699,
        "lng": 24.9384
      },
      "targetPosition": {
        "lat": 60.1708,
        "lng": 24.9384
      },
      "flightPath": [
        { "order": 0, "lat": 60.1701, "lng": 24.9384 },
        { "order": 1, "lat": 60.1703, "lng": 24.9384 },
        { "order": 2, "lat": 60.1706, "lng": 24.9384 }
      ]
    },
    {
      "number": 2,
      "teePosition": {
        "lat": 60.1708,
        "lng": 24.9384
      },
      "targetPosition": {
        "lat": 60.1718,
        "lng": 24.9384
      }
    }
  ]
}

Minimal Request (name only):

{
  "externalCourseId": "your-app-course-id",
  "name": "New Course Name"
}

Request with location only (no fairways):

{
  "externalCourseId": "your-app-course-id",
  "name": "New Course Name",
  "location": {
    "lat": 60.1699,
    "lng": 24.9384
  }
}

Response (with fairways):

{
  "id": "course_123",
  "externalCourseId": "your-app-course-id",
  "name": "New Course Name",
  "location": {
    "lat": 60.1699,
    "lng": 24.9384
  },
  "studioUrl": "/studio/destinations/dest_456/courses/course_123",
  "fairways": [
    {
      "id": "fairway_1",
      "number": 1,
      "par": 3,
      "distance": 100,
      "teePosition": {
        "lat": 60.1699,
        "lng": 24.9384
      },
      "targetPosition": {
        "lat": 60.1708,
        "lng": 24.9384
      },
      "flightPath": null
    },
    {
      "id": "fairway_2",
      "number": 2,
      "par": 3,
      "distance": 111,
      "teePosition": {
        "lat": 60.1708,
        "lng": 24.9384
      },
      "targetPosition": {
        "lat": 60.1718,
        "lng": 24.9384
      },
      "flightPath": null
    }
  ],
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T10:00:00Z"
}

Response (without fairways):

{
  "id": "course_123",
  "externalCourseId": "your-app-course-id",
  "name": "New Course Name",
  "location": {
    "lat": 60.1699,
    "lng": 24.9384
  },
  "studioUrl": "/studio/destinations/dest_456/courses/course_123",
  "fairways": [],
  "createdAt": "2025-01-15T10:00:00Z",
  "updatedAt": "2025-01-15T10:00:00Z"
}

Input fields of a fairway:

FieldTypeRequiredDescription
numbernumberYesHole number (1-27)
teePositionobjectYesCoordinates of the Tee {lat, lng}
targetPositionobjectYesCoordinates of the Target {lat, lng}
flightPatharrayNoControl points of the Flight Path [{order, lat, lng}]

Validation rules for fairways:

  • The fairways array is optional. You can omit it or leave it empty.
  • A course has at most 27 fairways.
  • Each fairway number is unique in the course.
  • Each fairway number is from 1 to 27.
  • Coordinates are valid: latitude -90 to 90, longitude -180 to 180.
  • The Tee and the Target are at least 0.1 meters apart.
  • The maximum distance between the Tee and the Target is 1000 meters.
  • All fairways fit in an area of 5 km². This keeps them compatible with the map area selection.
  • Parkdly calculates these values:
    • distance: the haversine distance from the Tee to the Target, in meters.
    • par: estimated from the distance (less than 150 m = 3, less than 250 m = 4, otherwise 5).

Rules for the Flight Path:

  • flightPath is optional for each fairway. When you omit it, Parkdly generates one control point at the midpoint.
  • The format of flightPath is the same as in the GET response: [{order, lat, lng}].
  • The order of control points starts at 0 and increases by 1, with no gaps and no duplicates.
  • A fairway has 1 to 50 control points.
  • Coordinates are valid: latitude -90 to 90, longitude -180 to 180.

Data Model

Course Object

FieldTypeDescription
idstringParkdly course ID
externalCourseIdstringYour app's course identifier
namestringCourse name
locationobject | nullCourse location {lat, lng}. Used as default map center in Parkdly Studio.
studioUrlstringRelative path to the course editor in Parkdly Studio. Add your Parkdly host (for example https://parkdly.com) before it to open it in a browser.
fairwaysarrayFairway objects (see below)
createdAtstringISO 8601 timestamp
updatedAtstringISO 8601 timestamp

Fairway Object

FieldTypeDescription
idstringID of the fairway
numbernumberHole number (1-18+)
parnumber | nullPar of the Hole
distancenumber | nullDistance in meters
teePositionobject | nullCoordinates of the Tee {lat, lng}
targetPositionobject | nullCoordinates of the Target {lat, lng}
flightPatharray | nullOrdered control points of the primary Flight Path (see below)

Flight Path Control Point

FieldTypeDescription
ordernumberControl point sequence (0-indexed, ascending from tee to target)
latnumberLatitude
lngnumberLongitude

Notes:

  • All distance values are in meters.
  • flightPath returns only the primary Flight Path. It shows the recommended path of the disc.
  • flightPath is null if the fairway has no Flight Path.
  • teePosition and targetPosition are null if they are not set.
  • Control points are in ascending order. Order 0 is closest to the Tee. Higher numbers are closer to the Target.
  • The complete Flight Path is: Tee → control points (in order) → Target.

Response Format

Success (2xx): Returns the data object directly

Error (4xx/5xx):

{
  "error": "error_code",
  "message": "Human readable error message"
}

Rate Limiting

See Rate Limits for the request limits.

Next Steps