{
	"openapi": "3.0.0",
	"info": {
		"description": "Read & Write activities on behalf of Relive users",
		"license": {
			"name": "https://www.relive.com/developers"
		},
		"title": "Relive API",
		"version": "1.0"
	},
	"paths": {
		"/upload": {
			"post": {
				"operationId": "UploadUpload",
				"responses": {
					"200": {
						"description": "",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"id": {
											"type": "string",
											"description": ""
										}
									}
								}
							}
						}
					}
				},
				"description": "Uploads a new activity from a data file.\nScope required: activity:write.",
				"security": [
					{
						"relive_oauth": [
							"\"activity:write\""
						]
					}
				],
				"requestBody": {
					"content": {
						"multipart/form-data": {
							"schema": {
								"type": "object",
								"properties": {
									"file": {
										"description": "The uploaded file as part of multipart form-data. The corresponding mime type must be one of:\n- application/gpx+xml\n- application/vnd.garmin.tcx+xml\n- application/vnd.ant.fit",
										"type": "string",
										"format": "binary"
									},
									"external_id": {
										"description": "The external identifier of the activity",
										"type": "string"
									},
									"name": {
										"description": "The title of the activity",
										"type": "string"
									},
									"type": {
										"description": "The type of the activity (ride, run, hike, ski, snowboard, other)",
										"type": "string",
										"enum": [
											"ride",
											"run",
											"hike",
											"ski",
											"snowboard",
											"other"
										]
									}
								},
								"required": [
									"file",
									"external_id"
								]
							}
						}
					}
				}
			}
		},
		"/upload/{id}": {
			"get": {
				"operationId": "UploadGetUpload",
				"responses": {
					"200": {
						"description": "",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/UploadResponse"
								}
							}
						}
					}
				},
				"description": "Scope required: activity:write.",
				"security": [
					{
						"relive_oauth": [
							"\"activity:write\""
						]
					}
				],
				"parameters": [
					{
						"description": "",
						"in": "path",
						"name": "id",
						"required": true,
						"schema": {
							"type": "string"
						}
					}
				]
			}
		},
		"/user/": {
			"get": {
				"operationId": "UserUser",
				"responses": {
					"200": {
						"description": "Ok",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/UserResponse"
								}
							}
						}
					}
				},
				"description": "Returns a representation of a user for the authenticated user.\n\nScope required: user:read or activity:read.",
				"security": [
					{
						"relive_oauth": [
							"\"user:read\""
						]
					}
				]
			}
		},
		"/user/activities": {
			"get": {
				"operationId": "UserGetActivities",
				"responses": {
					"200": {
						"description": "Ok",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/ActivitiesResponse"
								}
							}
						}
					}
				},
				"description": "Returns the activities by a specific user,\nsorted by activity start date,\nmost recent first.\n\nScope required: activity:read.",
				"security": [
					{
						"relive_oauth": [
							"\"activity:read\""
						]
					}
				],
				"parameters": [
					{
						"description": "",
						"in": "query",
						"name": "pagination_token",
						"required": false,
						"schema": {
							"type": "string"
						}
					}
				]
			}
		},
		"/activity/{id}": {
			"get": {
				"operationId": "ActivityGetActivity",
				"responses": {
					"200": {
						"description": "Ok",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Activity"
								}
							}
						}
					}
				},
				"description": "Return detailed information about a specific activity\n\nScope required: activity:read.",
				"security": [
					{
						"relive_oauth": [
							"\"activity:read\""
						]
					}
				],
				"parameters": [
					{
						"description": "id of the activity",
						"in": "path",
						"name": "id",
						"required": true,
						"schema": {
							"type": "string"
						}
					}
				]
			}
		},
		"/activity/{id}/render": {
			"post": {
				"operationId": "ActivityRenderActivity",
				"responses": {
					"200": {
						"description": "Ok",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/Activity"
								}
							}
						}
					}
				},
				"description": "Render a specific activity. Only available for specific clients.",
				"security": [
					{
						"relive_oauth": [
							"\"activity:write\""
						]
					}
				],
				"parameters": [
					{
						"description": "id of the activity",
						"in": "path",
						"name": "id",
						"required": true,
						"schema": {
							"type": "string"
						}
					}
				]
			}
		},
		"/activity/{id}/map": {
			"get": {
				"operationId": "ActivityGetActivityMap",
				"responses": {
					"204": {
						"description": "No content"
					}
				},
				"description": "Returns a static map image with the activity route drawn on it.",
				"parameters": [
					{
						"description": "Activity ID",
						"in": "path",
						"name": "id",
						"required": true,
						"schema": {
							"type": "string"
						}
					}
				]
			}
		},
		"/activity/{id}/moment-map/{encodedLocation}": {
			"get": {
				"operationId": "ActivityGetActivityMomentMap",
				"responses": {
					"204": {
						"description": "No content"
					}
				},
				"description": "Returns a static map image with the activity route and a marker at the given moment location.",
				"parameters": [
					{
						"description": "Activity ID",
						"in": "path",
						"name": "id",
						"required": true,
						"schema": {
							"type": "string"
						}
					},
					{
						"description": "Base64url-encoded \"lat,lon\" of the moment to display",
						"in": "path",
						"name": "encodedLocation",
						"required": true,
						"schema": {
							"type": "string"
						}
					}
				]
			}
		},
		"/oauth/token": {
			"post": {
				"operationId": "AuthToken",
				"responses": {
					"200": {
						"description": "",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/TokenResponse"
								}
							}
						}
					}
				},
				"description": "Exchanges a temporary OAuth verifier code, or a refresh_token for an access token.\nhttps://tools.ietf.org/html/rfc6749#section-3.2",
				"requestBody": {
					"content": {
						"application/x-www-form-urlencoded": {
							"schema": {
								"type": "object",
								"properties": {
									"client_id": {
										"description": "Issued when you created your application.",
										"type": "string"
									},
									"client_secret": {
										"description": "Issued when you created your application.",
										"type": "string"
									},
									"grant_type": {
										"type": "string",
										"enum": [
											"authorization_code",
											"refresh_token"
										]
									},
									"code": {
										"description": "REQUIRED when grant_type is \"authorization_code\". The `code` param returned via the OAuth callback.",
										"type": "string"
									},
									"redirect_uri": {
										"description": "REQUIRED when grant_type is \"authorization_code\". Ensure that the \"redirect_uri\" parameter is present if the \"redirect_uri\" parameter was included in the initial authorization",
										"type": "string"
									},
									"refresh_token": {
										"description": "REQUIRED when grant_type is \"refresh_token\".",
										"type": "string"
									}
								},
								"required": [
									"client_id",
									"client_secret",
									"grant_type"
								]
							}
						}
					}
				}
			}
		},
		"/oauth/deauthorize": {
			"post": {
				"operationId": "AuthDeauthorize",
				"responses": {
					"200": {
						"description": "Ok",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/DeauthorizationResponse"
								}
							}
						}
					},
					"204": {
						"description": "",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/DeauthorizationResponse"
								}
							}
						}
					}
				},
				"description": "Deauthorizes all refresh tokens for this user and client_id.\nExisting access tokens are still valid until expiry. Suggest to delete those on the third-party side.",
				"security": [
					{
						"relive_oauth": [
							"\"activity:write\"",
							"\"activity:read\"",
							"\"user:read\""
						]
					}
				]
			}
		}
	},
	"servers": [
		{
			"url": "https://public.api.relive.cc/v1"
		}
	],
	"components": {
		"securitySchemes": {
			"relive_oauth": {
				"type": "oauth2",
				"flows": {
					"authorizationCode": {
						"authorizationUrl": "https://www.relive.com/oauth/authorize",
						"tokenUrl": "/v1/oauth/token",
						"scopes": {
							"activity:read": "Read the user's activity data.",
							"user:read": "Read the user's profile data.",
							"activity:write": "Upload activities on behalf of the user"
						}
					}
				}
			}
		},
		"schemas": {
			"UploadResponse": {
				"description": "",
				"properties": {
					"id": {
						"type": "string",
						"description": "Upload id, generated."
					},
					"name": {
						"type": "string",
						"description": "Name provided on upload."
					},
					"type": {
						"type": "string",
						"description": "Activity type provided on upload."
					},
					"external_id": {
						"type": "string",
						"description": "external_id as provided in the POST."
					},
					"status": {
						"type": "object",
						"description": "Processing status for the upload.\n\n  | \"done\"\n\n  | \"processing\"\n\n  | \"failed\""
					},
					"activity_id": {
						"type": "string",
						"description": "Relive activity_id. Corresponds to id in activity API."
					},
					"status_reason": {
						"type": "string",
						"description": "Exposes optional status in case the upload has failed to process. In this case, no activity will be created either.\n\n  | \"An overlapping activity already exists.\"\n\n  | \"An activity with this provider + external_id already exists.\"\n\n  | \"This upload is missing vital data, like timestamps.\""
					}
				},
				"type": "object",
				"required": [
					"id",
					"external_id",
					"status"
				]
			},
			"UserResponse": {
				"description": "",
				"properties": {
					"user_id": {
						"type": "string",
						"description": ""
					},
					"country": {
						"type": "string",
						"description": ""
					},
					"display_name": {
						"type": "string",
						"description": ""
					},
					"language": {
						"type": "string",
						"description": ""
					},
					"email": {
						"type": "string",
						"description": ""
					}
				},
				"type": "object",
				"required": [
					"user_id",
					"display_name",
					"language"
				]
			},
			"Activity": {
				"description": "",
				"properties": {
					"id": {
						"type": "string",
						"description": ""
					},
					"state": {
						"type": "string",
						"enum": [
							"failed",
							"done",
							"editing",
							"pending-render",
							"blocked-premium"
						],
						"description": ""
					},
					"activity_at": {
						"type": "string",
						"description": ""
					},
					"type": {
						"type": "string",
						"description": ""
					},
					"moving_time": {
						"type": "number",
						"format": "double",
						"description": ""
					},
					"distance": {
						"type": "number",
						"format": "double",
						"description": ""
					},
					"elevation_gain": {
						"type": "number",
						"format": "double",
						"description": ""
					},
					"name": {
						"type": "string",
						"description": ""
					},
					"url": {
						"type": "string",
						"description": ""
					},
					"poster_square": {
						"type": "object",
						"properties": {
							"url": {
								"type": "string",
								"description": ""
							},
							"resize_url": {
								"type": "string",
								"description": ""
							}
						},
						"description": ""
					},
					"poster": {
						"type": "object",
						"properties": {
							"url": {
								"type": "string",
								"description": ""
							},
							"resize_url": {
								"type": "string",
								"description": ""
							}
						},
						"description": ""
					},
					"map": {
						"type": "object",
						"properties": {
							"url": {
								"type": "string",
								"description": ""
							},
							"resize_url": {
								"type": "string",
								"description": ""
							}
						},
						"description": ""
					},
					"moments": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"moment_at": {
									"type": "string",
									"description": ""
								},
								"location": {
									"type": "object",
									"properties": {
										"lat": {
											"type": "number",
											"format": "double",
											"description": ""
										},
										"lon": {
											"type": "number",
											"format": "double",
											"description": ""
										},
										"distance": {
											"type": "number",
											"format": "double",
											"description": ""
										},
										"map": {
											"type": "object",
											"properties": {
												"url": {
													"type": "string",
													"description": ""
												},
												"resize_url": {
													"type": "string",
													"description": ""
												}
											},
											"description": ""
										}
									},
									"description": ""
								},
								"media": {
									"type": "array",
									"items": {
										"type": "object"
									},
									"description": ""
								}
							}
						},
						"description": ""
					}
				},
				"type": "object",
				"required": [
					"id",
					"state",
					"activity_at",
					"type",
					"moving_time",
					"distance",
					"elevation_gain",
					"name",
					"moments"
				]
			},
			"ActivitiesResponse": {
				"description": "",
				"properties": {
					"next_pagination_token": {
						"type": "string",
						"description": ""
					},
					"activities": {
						"type": "array",
						"items": {
							"$ref": "#/components/schemas/Activity"
						},
						"description": ""
					}
				},
				"type": "object",
				"required": [
					"next_pagination_token",
					"activities"
				]
			},
			"DeauthorizationResponse": {
				"description": "",
				"properties": {},
				"type": "object"
			},
			"TokenResponse": {
				"description": "https://tools.ietf.org/html/rfc6749#section-5.1",
				"properties": {
					"access_token": {
						"type": "string",
						"description": "The access token issued by the authorization server."
					},
					"refresh_token": {
						"type": "string",
						"description": "The refresh token, which can be used to obtain new access tokens using the same authorization grant as described in Section 6.\n\nOptional; the server MAY issue a new refresh_token, in this case the consumer should replace the existing refresh_token"
					},
					"scope": {
						"type": "string",
						"description": "The scope of the access token as described by Section 3.3. Space separated."
					},
					"token_type": {
						"type": "string",
						"description": "The type of the token issued as described in Section 7.1. Value is case insensitive. Will be \"Bearer\""
					},
					"expires_in": {
						"type": "number",
						"format": "double",
						"description": "The lifetime in seconds of the access token.  For example, the value \"3600\" denotes that the access token will expire in one hour from the time the response was generated."
					}
				},
				"type": "object",
				"required": [
					"access_token",
					"scope",
					"token_type",
					"expires_in"
				]
			}
		}
	}
}