API to easily extract data from websites. # Base URL All URLs referenced in the documentation have the following base: ``` https://api.link.fish ``` The REST API is only served over HTTPS. To ensure data privacy, unencrypted HTTP is not supported. # Authentication HTTP requests to the REST API are protected with [HTTP Basic authentication](https://en.wikipedia.org/wiki/Basic_access_authentication). You will use the email address of your link.fish account as the username and your API access token as the password for HTTP Basic authentication. If you do not have an account yet, go to [https://link.fish/api](https://link.fish/api) and create one first. You will receive the API access token automatically via email after you signed up. To generate a new token and invalidate the current one log into your link.fish account at [https://app.link.fish](https://app.link.fish) and go to: "Plugins" -> "API Dashboard" There you can also see how many credits you used already. # Errors The API uses standard HTTP status codes to indicate the success or failure of the API call. The body of the response will be JSON in the following format: ``` { "status": {HTTP STATUS CODE} "message": "{ERROR MESSAGE}" } ``` Like for example when the authorization is not provided or wrong: ``` { "status": 401 "message": "Unauthorized" } ``` # Request IDs Each API request has an associated request identifier. You can find it in the response headers, under X-LF-Request-Id. In case you have problems please provide this identifier that we can help you as good and fast as possible. Example: ``` X-LF-Request-Id: f7f0036f-5277-421a-b143-f7a151571d18 ``` # Item format The data is by default deeply nested. So if it should be checked if there is an offer with a price, the whole tree has to be checked. To make that simpler, it is also possible to return the data "flat". If selected it will flatten the tree by copying all the data to the main level under a property with the name of its type and link the data internally. Information: We created a node module which allows converting between the two formats. It did not get open sourced yet. If you are in need, simply contact us via api@link.fish. # Response Content Type By default, all data gets returned as JSON. If the data should be returned as XML add the following header: ``` Accept: application/xml ``` # Credits Depending on the request made a different amount of credits get charged. How many which request costs can be found on the [API pricing page](http://link.fish/api/#pricing). Additionally, does a header named "X-LF-Credits-Charged" get added to each successful response with information about the credits. Example: ``` X-LF-Credits-Charged: 1 # Credits used for current requests X-LF-Credits-Subscription-Max: 1000 # Total credits available in subscription X-LF-Credits-Subscription-Used: 512 # Credits still left in current month ``` You can check anytime how many credits you did use already by logging into your link.fish account at [https://app.link.fish](https://app.link.fish) and checking under: "Plugins" -> "API Dashboard" If you have problems, questions or improvement advice please send us an email to api@link.fish
## Introduction The Linode API provides the ability to programmatically manage the full range of Linode products and services. This reference is designed to assist application developers and system administrators. Each endpoint includes descriptions, request syntax, and examples using standard HTTP requests. Response data is returned in JSON format. This document was generated from our OpenAPI Specification. See the OpenAPI website for more information. Download the Linode OpenAPI Specification. ## Changelog View our Changelog to see release notes on all changes made to our API. ## Access and Authentication Some endpoints are publicly accessible without requiring authentication. All endpoints affecting your Account, however, require either a Personal Access Token or OAuth authentication (when using third-party applications). ### Personal Access Token The easiest way to access the API is with a Personal Access Token (PAT) generated from the Linode Cloud Manager or the [Create Personal Access Token](/docs/api/profile/#personal-access-token-create) endpoint. All scopes for the OAuth security model ([defined below](/docs/api/profile/#oauth)) apply to this security model as well. #### Authentication | Security Scheme Type: | HTTP | |-----------------------|------| | **HTTP Authorization Scheme** | bearer | ### OAuth If you only need to access the Linode API for personal use, we recommend that you create a [personal access token](/docs/api/#personal-access-token). If you're designing an application that can authenticate with an arbitrary Linode user, then you should use the OAuth 2.0 workflows presented in this section. For a more detailed example of an OAuth 2.0 implementation, see our guide on [How to Create an OAuth App with the Linode Python API Library](/docs/products/tools/api/guides/create-an-oauth-app-with-the-python-api-library/#oauth-2-authentication-exchange). Before you implement OAuth in your application, you first need to create an OAuth client. You can do this [with the Linode API](/docs/api/account/#oauth-client-create) or [via the Cloud Manager](https://cloud.linode.com/profile/clients): - When creating the client, you'll supply a `label` and a `redirect_uri` (referred to as the Callback URL in the Cloud Manager). - The response from this endpoint will give you a `client_id` and a `secret`. - Clients can be public or private, and are private by default. You can choose to make the client public when it is created. - A private client is used with applications which can securely store the client secret (that is, the secret returned to you when you first created the client). For example, an application running on a secured server that only the developer has access to would use a private OAuth client. This is also called a confidential client in some OAuth documentation. - A public client is used with applications where the client secret is not guaranteed to be secure. For example, a native app running on a user's computer may not be able to keep the client secret safe, as a user could potentially inspect the source of the application. So, native apps or apps that run in a user's browser should use a public client. - Public and private clients follow different workflows, as described below. #### OAuth Workflow The OAuth workflow is a series of exchanges between your third-party app and Linode. The workflow is used to authenticate a user before an application can start making API calls on the user's behalf. Notes: - With respect to the diagram in [section 1.2 of RFC 6749](https://tools.ietf.org/html/rfc6749#section-1.2), login.linode.com (referred to in this section as the *login server*) is the Resource Owner and the Authorization Server; api.linode.com (referred to here as the *api server*) is the Resource Server. - The OAuth spec refers to the private and public workflows listed below as the [authorization code flow](https://tools.ietf.org/html/rfc6749#section-1.3.1) and [implicit flow](https://tools.ietf.org/html/rfc6749#section-1.3.2). | PRIVATE WORKFLOW | PUBLIC WORKFLOW | |------------------|------------------| | 1. The user visits the application's website and is directed to login with Linode. | 1. The user visits the application's website and is directed to login with Linode. | | 2. Your application then redirects the user to Linode's [login server](https://login.linode.com) with the client application's `client_id` and requested OAuth `scope`, which should appear in the URL of the login page. | 2. Your application then redirects the user to Linode's [login server](https://login.linode.com) with the client application's `client_id` and requested OAuth `scope`, which should appear in the URL of the login page. | | 3. The user logs into the login server with their username and password. | 3. The user logs into the login server with their username and password. | | 4. The login server redirects the user to the specificed redirect URL with a temporary authorization `code` (exchange code) in the URL. | 4. The login server redirects the user back to your application with an OAuth `access_token` embedded in the redirect URL's hash. This is temporary and expires in two hours. No `refresh_token` is issued. Therefore, once the `access_token` expires, a new one will need to be issued by having the user log in again. | | 5. The application issues a POST request (*see additional details below*) to the login server with the exchange code, `client_id`, and the client application's `client_secret`. | | | 6. The login server responds to the client application with a new OAuth `access_token` and `refresh_token`. The `access_token` is set to expire in two hours. | | | 7. The `refresh_token` can be used by contacting the login server with the `client_id`, `client_secret`, `grant_type`, and `refresh_token` to get a new OAuth `access_token` and `refresh_token`. The new `access_token` is good for another two hours, and the new `refresh_token` can be used to extend the session again by this same method (*see additional details below*). | | #### OAuth Private Workflow - Additional Details The following information expands on steps 5 through 7 of the private workflow: Once the user has logged into Linode and you have received an exchange code, you will need to trade that exchange code for an `access_token` and `refresh_token`. You do this by making an HTTP POST request to the following address: ``` https://login.linode.com/oauth/token ``` Make this request as `application/x-www-form-urlencoded` or as `multipart/form-data` and include the following parameters in the POST body: | PARAMETER | DESCRIPTION | |-----------|-------------| | client_id | Your app's client ID. | | client_secret | Your app's client secret. | | code | The code you just received from the redirect. | You'll get a response like this: ```json { "scope": "linodes:read_write", "access_token": "03d084436a6c91fbafd5c4b20c82e5056a2e9ce1635920c30dc8d81dc7a6665c", "refresh_token": "f2ec9712e616fdb5a2a21aa0e88cfadea7502ebc62cf5bd758dbcd65e1803bad", "token_type": "bearer", "expires_in": 7200 } ``` Included in the response is an `access_token`. With this token, you can proceed to make authenticated HTTP requests to the API by adding this header to each request: ``` Authorization: Bearer 03d084436a6c91fbafd5c4b20c82e5056a2e9ce1635920c30dc8d81dc7a6665c ``` This `access_token` is set to expire in two hours. To refresh access prior to expiration, make another request to the same URL with the following parameters in the POST body: | PARAMETER | DESCRIPTION | |-----------|-------------| | grant_type | The grant type you're using. Use "refresh_token" when refreshing access. | | client_id | Your app's client ID. | | client_secret | Your app's client secret. | | refresh_token | The `refresh_token` received from the previous response. | You'll get another response with an updated `access_token` and `refresh_token`, which can then be used to refresh access again. #### OAuth Reference | Security Scheme Type | OAuth 2.0 | |-----------------------|--------| | **Authorization URL** | https://login.linode.com/oauth/authorize | | **Token URL** | https://login.linode.com/oauth/token | | **Scopes** |
- `account:read_only` - Allows access to GET information about your Account.
- `account:read_write` - Allows access to all endpoints related to your Account.
- `databases:read_only` - Allows access to GET Managed Databases on your Account.
- `databases:read_write` - Allows access to all endpoints related to your Managed Databases.
- `domains:read_only` - Allows access to GET Domains on your Account.
- `domains:read_write` - Allows access to all Domain endpoints.
- `events:read_only` - Allows access to GET your Events.
- `events:read_write` - Allows access to all endpoints related to your Events.
- `firewall:read_only` - Allows access to GET information about your Firewalls.
- `firewall:read_write` - Allows access to all Firewall endpoints.
- `images:read_only` - Allows access to GET your Images.
- `images:read_write` - Allows access to all endpoints related to your Images.
- `ips:read_only` - Allows access to GET your ips.
- `ips:read_write` - Allows access to all endpoints related to your ips.
- `linodes:read_only` - Allows access to GET Linodes on your Account.
- `linodes:read_write` - Allow access to all endpoints related to your Linodes.
- `lke:read_only` - Allows access to GET LKE Clusters on your Account.
- `lke:read_write` - Allows access to all endpoints related to LKE Clusters on your Account.
- `longview:read_only` - Allows access to GET your Longview Clients.
- `longview:read_write` - Allows access to all endpoints related to your Longview Clients.
- `nodebalancers:read_only` - Allows access to GET NodeBalancers on your Account.
- `nodebalancers:read_write` - Allows access to all NodeBalancer endpoints.
- `object_storage:read_only` - Allows access to GET information related to your Object Storage.
- `object_storage:read_write` - Allows access to all Object Storage endpoints.
- `stackscripts:read_only` - Allows access to GET your StackScripts.
- `stackscripts:read_write` - Allows access to all endpoints related to your StackScripts.
- `volumes:read_only` - Allows access to GET your Volumes.
- `volumes:read_write` - Allows access to all endpoints related to your Volumes.
| ## Requests Requests must be made over HTTPS to ensure transactions are encrypted. The following Request methods are supported: | METHOD | USAGE | |--------|-------| | GET | Retrieves data about collections and individual resources. | | POST | For collections, creates a new resource of that type. Also used to perform actions on action endpoints. | | PUT | Updates an existing resource. | | DELETE | Deletes a resource. This is a destructive action. | ## Responses Actions will return one following HTTP response status codes: | STATUS | DESCRIPTION | |---------|-------------| | 200 OK | The request was successful. | | 202 Accepted | The request was successful, but processing has not been completed. The response body includes a "warnings" array containing the details of incomplete processes. | | 204 No Content | The server successfully fulfilled the request and there is no additional content to send. | | 299 Deprecated | The request was successful, but involved a deprecated endpoint. The response body includes a "warnings" array containing warning messages. | | 400 Bad Request | You submitted an invalid request (missing parameters, etc.). | | 401 Unauthorized | You failed to authenticate for this resource. | | 403 Forbidden | You are authenticated, but don't have permission to do this. | | 404 Not Found | The resource you're requesting does not exist. | | 429 Too Many Requests | You've hit a rate limit. | | 500 Internal Server Error | Please [open a Support Ticket](/docs/api/support/#support-ticket-open). | ## Errors Success is indicated via Standard HTTP status codes. `2xx` codes indicate success, `4xx` codes indicate a request error, and `5xx` errors indicate a server error. A request error might be an invalid input, a required parameter being omitted, or a malformed request. A server error means something went wrong processing your request. If this occurs, please [open a Support Ticket](/docs/api/support/#support-ticket-open) and let us know. Though errors are logged and we work quickly to resolve issues, opening a ticket and providing us with reproducable steps and data is always helpful. The `errors` field is an array of the things that went wrong with your request. We will try to include as many of the problems in the response as possible, but it's conceivable that fixing these errors and resubmitting may result in new errors coming back once we are able to get further along in the process of handling your request. Within each error object, the `field` parameter will be included if the error pertains to a specific field in the JSON you've submitted. This will be omitted if there is no relevant field. The `reason` is a human-readable explanation of the error, and will always be included. ## Pagination Resource lists are always paginated. The response will look similar to this: ```json { "data": [ ... ], "page": 1, "pages": 3, "results": 300 } ``` * Pages start at 1. You may retrieve a specific page of results by adding `?page=x` to your URL (for example, `?page=4`). If the value of `page` exceeds `2^64/page_size`, the last possible page will be returned. * Page sizes default to 100, and can be set to return between 25 and 500. Page size can be set using `?page_size=x`. ## Filtering and Sorting Collections are searchable by fields they include, marked in the spec as `x-linode-filterable: true`. Filters are passed in the `X-Filter` header and are formatted as JSON objects. Here is a request call for Linode Types in our "standard" class: ```Shell curl "https://api.linode.com/v4/linode/types" \ -H 'X-Filter: { "class": "standard" }' ``` The filter object's keys are the keys of the object you're filtering, and the values are accepted values. You can add multiple filters by including more than one key. For example, filtering for "standard" Linode Types that offer one vcpu: ```Shell curl "https://api.linode.com/v4/linode/types" \ -H 'X-Filter: { "class": "standard", "vcpus": 1 }' ``` In the above example, both filters are combined with an "and" operation. However, if you wanted either Types with one vcpu or Types in our "standard" class, you can add an operator: ```Shell curl "https://api.linode.com/v4/linode/types" \ -H 'X-Filter: { "+or": [ { "vcpus": 1 }, { "class": "standard" } ] }' ``` Each filter in the `+or` array is its own filter object, and all conditions in it are combined with an "and" operation as they were in the previous example. Other operators are also available. Operators are keys of a Filter JSON object. Their value must be of the appropriate type, and they are evaluated as described below: | OPERATOR | TYPE | DESCRIPTION | |----------|--------|-----------------------------------| | +and | array | All conditions must be true. | | +or | array | One condition must be true. | | +gt | number | Value must be greater than number. | | +gte | number | Value must be greater than or equal to number. | | +lt | number | Value must be less than number. | | +lte | number | Value must be less than or equal to number. | | +contains | string | Given string must be in the value. | | +neq | string | Does not equal the value. | | +order_by | string | Attribute to order the results by - must be filterable. | | +order | string | Either "asc" or "desc". Defaults to "asc". Requires `+order_by`. | For example, filtering for [Linode Types](/docs/api/linode-types/) that offer memory equal to or higher than 61440: ```Shell curl "https://api.linode.com/v4/linode/types" \ -H ' X-Filter: { "memory": { "+gte": 61440 } }' ``` You can combine and nest operators to construct arbitrarily-complex queries. For example, give me all [Linode Types](/docs/api/linode-types/) which are either `standard` or `highmem` class, or have between 12 and 20 vcpus: ```Shell curl "https://api.linode.com/v4/linode/types" \ -H ' X-Filter: { "+or": [ { "+or": [ { "class": "standard" }, { "class": "highmem" } ] }, { "+and": [ { "vcpus": { "+gte": 12 } }, { "vcpus": { "+lte": 20 } } ] } ] }' ``` ## Time Values All times returned by the API are in UTC, regardless of the timezone configured within your user's profile (see `timezone` property within [Profile View](/docs/api/profile/#profile-view__responses)). ## Rate Limiting Rate limits on API requests help maintain the health and stability of the Linode API. Accordingly, every endpoint of the Linode API applies a rate limit on a per user basis as determined by OAuth token for authenticated requests or IP address for public endpoints. Each rate limit consists of a total number of requests and a time window. For example, if an endpoint has a rate limit of 800 requests per minute, then up to 800 requests over a one minute window are permitted. Subsequent requests to an endpoint after hitting a rate limit return a 429 error. You can successfully remake requests to that endpoint after the rate limit window resets. ### Linode APIv4 Rate Limits With the Linode API, you can generally make up to 1,600 general API requests every two minutes. Additionally, all endpoints have a rate limit of 800 requests per minute unless otherwise specified below. **Note:** There may be rate limiting applied at other levels outside of the API, for example, at the load balancer. Creating Linodes has a dedicated rate limit of 10 requests per 30 seconds. That endpoint is: * [Linode Create](/docs/api/linode-instances/#linode-create) `/stats` endpoints have their own dedicated rate limits of 100 requests per minute. These endpoints are: * [View Linode Statistics](/docs/api/linode-instances/#linode-statistics-view) * [View Linode Statistics (year/month)](/docs/api/linode-instances/#statistics-yearmonth-view) * [View NodeBalancer Statistics](/docs/api/nodebalancers/#nodebalancer-statistics-view) * [List Managed Stats](/docs/api/managed/#managed-stats-list) Object Storage endpoints have a dedicated rate limit of 750 requests per second. The Object Storage endpoints are: * [Object Storage Endpoints](/docs/api/object-storage/) Opening Support Tickets has a dedicated rate limit of 2 requests per minute. That endpoint is: * [Open Support Ticket](/docs/api/support/#support-ticket-open) Accepting Service Transfers has a dedicated rate limit of 2 requests per minute. That endpoint is: * [Service Transfer Accept](/docs/api/account/#service-transfer-accept) ### Rate Limit HTTP Response Headers The Linode API includes the following HTTP response headers which are designed to help you avoid hitting rate limits that might disrupt your applications: * **X-RateLimit-Limit**: The maximum number of permitted requests during the rate limit window for this endpoint. * **X-RateLimit-Remaining**: The remaining number of permitted requests in the current rate limit window. * **X-RateLimit-Reset**: The time when the current rate limit window rests in UTC epoch seconds. * **Retry-After**: The remaining time in seconds until the current rate limit window resets. There are many ways to access header information for your requests, depending on how you are accessing the Linode API. For example, to view HTTP response headers when making requests with `curl`, use the `-i` or `--include` option as follows: ```Shell curl -i https://api.linode.com/v4/regions ``` ## CLI (Command Line Interface) The Linode CLI allows you to easily work with the API using intuitive and simple syntax. It requires a [Personal Access Token](/docs/api/#personal-access-token) for authentication, and gives you access to all of the features and functionality of the Linode API that are documented here with CLI examples. Endpoints that do not have CLI examples are currently unavailable through the CLI, but can be accessed via other methods such as Shell commands and other third-party applications.
This is LinQR QR Code API documentation. This API allows you to generate custom, visually attractive QR Codes. The cloud infrastructure guarantees high availability and autoscalability of the service. You can generate hundreds of thousands of images this way and use them however you like. We realize that your API use case may require custom solutions, and perhaps we lack functionality that is very important to you. In that case feel free to write an email to our support and tell us about it. We have repeatedly added new functions of our service directly after the requests of our users. **General remarks:** - maximum request size is fixed at 32MB. - request timeout is fixed at 180 seconds.
[DFlight API](https://ljaero.com/solutions/dflight/) supplies the up-to-date information needed for compliance with UAV preflight assessment requirements. Separate endpoints are available for each of the following information categories: - Airspace - Weather - Temporary Flight Restrictions - Special Security Areas - Restricted Public Venues - Surface Obstacles - Aerodromes - UAS Operating Areas You can define your geographic area of interest in one of three convenient ways: - Providing a latitude/longitude point and distance around that point - Providing a GeoJSON LineString defining your route - Providing an arbitrary GeoJSON Polygon defining your area of interest
**Is this your first time here? Please check out our [introduction to Loket (API)](./Introduction)** **The initial loading time of this developer portal may be very long due to the large number of endpoints designs being rendered when loading the page. We are looking into an alternative solution but for now please bear in mind.** # General The Loket.nl API is a RESTful API that exposes the data and features of the Loket.nl platform. The API accepts and returns JSON and can only be accessed by registered users. This documentation describes version 2 of the API. Are you looking to partner up and start building an integration based on the Loket RESTful API? Please check out the steps for partners on our [website](https://www.loket.nl/koppelingen/koppelen-met-loket/) . Have you received your client and user credentials from us? Check out the following Postman collection to help you start making your first API calls on our acceptance environment. We would recommend to install the Postman desktop app. [![Run in Postman](https://run.pstmn.io/button.svg)](https://god.gw.postman.com/run-collection/19604713-42728000-2df3-4ff0-908e-dc6ab410990c?action=collection%2Ffork&collection-url=entityId%3D19604713-42728000-2df3-4ff0-908e-dc6ab410990c%26entityType%3Dcollection%26workspaceId%3Ddde2c409-9fb2-4f40-9981-f937f73750ea#?env%5BLoket.nl%20Test%20Environment%5D=W3sia2V5IjoiQXV0aGVudGljYXRpb25TZXJ2ZXJVcmwiLCJ2YWx1ZSI6Imh0dHBzOi8vb2F1dGgubG9rZXQtYWNjLm5sLyIsImVuYWJsZWQiOnRydWUsInR5cGUiOiJ0ZXh0Iiwic2Vzc2lvblZhbHVlIjoiaHR0cHM6Ly9vYXV0aC5sb2tldC1hY2MubmwvIiwic2Vzc2lvbkluZGV4IjowfSx7ImtleSI6Ikxva2V0QXBpVXJsIiwidmFsdWUiOiJodHRwczovL2FwaS5sb2tldC1hY2MubmwvIiwiZW5hYmxlZCI6dHJ1ZSwidHlwZSI6InRleHQiLCJzZXNzaW9uVmFsdWUiOiJodHRwczovL2FwaS5sb2tldC1hY2MubmwvIiwic2Vzc2lvbkluZGV4IjoxfSx7ImtleSI6IkNsaWVudF9JZCIsInZhbHVlIjoiIiwiZW5hYmxlZCI6dHJ1ZSwidHlwZSI6InRleHQiLCJzZXNzaW9uVmFsdWUiOiIiLCJzZXNzaW9uSW5kZXgiOjJ9LHsia2V5IjoiQ2xpZW50X1NlY3JldCIsInZhbHVlIjoiIiwiZW5hYmxlZCI6dHJ1ZSwidHlwZSI6InRleHQiLCJzZXNzaW9uVmFsdWUiOiIiLCJzZXNzaW9uSW5kZXgiOjN9LHsia2V5IjoiUmVkaXJlY3RfVXJpIiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlLCJ0eXBlIjoidGV4dCIsInNlc3Npb25WYWx1ZSI6IiIsInNlc3Npb25JbmRleCI6NH0seyJrZXkiOiJyZWZyZXNoX3Rva2VuIiwidmFsdWUiOiIiLCJlbmFibGVkIjp0cnVlLCJ0eXBlIjoidGV4dCIsInNlc3Npb25WYWx1ZSI6IiIsInNlc3Npb25JbmRleCI6NX0seyJrZXkiOiJ0b2tlbiIsInZhbHVlIjoiIiwiZW5hYmxlZCI6dHJ1ZSwidHlwZSI6InRleHQiLCJzZXNzaW9uVmFsdWUiOiIiLCJzZXNzaW9uSW5kZXgiOjZ9XQ==) Do you want to contact us with any further questions or remarks regarding the Loket RESTful API? Please send an email to api@loket.nl, and we will get back to you. ## Environments The Loket.nl API has two different environments. The first environment is the "acceptance" environment which is used during development and returns test data. The second environment is the production environment which is to be used exclusively by approved applications. Both environments have their own URLs. * The acceptance environment can be accessed at https://api.loket-acc.nl/v2/ * The production environment can be accessed at https://api.loket.nl/v2/ ## OpenAPI documentation The endpoints are defined using the [OpenAPI 3.0 specification](https://github.com/OAI/OpenAPI-Specification), an industry-wide recognized standard for describing REST API's. __Please note:__ the endpoint documentation in this portal is not designed to be fully compatible with any automatic code generation tools. ## Change policy Over the course of time the API, and policies regarding the API can and will change. These changes are subject to the following guidelines. The following states hold true for the change policy for this API. * Loket.nl may sometimes introduce changes to the API and policies without advance notice. * Loket.nl will try to inform users of any (breaking) change in advance. * Loket.nl will not be liable to you or any third party for such modifications or any adverse effects resulting from such modifications. * Loket.nl will try to avoid breaking changes as much as possible. ## Notification periods In regard to changes Loket.nl will strive to adhere to the following notification periods per type of change. Due to our versioning strategy at resource level this API has the possibility to run multiple versions of the same resource at one time. This allows for a window in which both the old and new version are available. Allowing for a gradual move to the new version. | Type of change | Notification period | Support period old version | |------------------|---------------|---------------| | Non breaking change | 2 weeks | no new version | | Breaking change | 2 weeks | 6 months | | Critical | Due to the nature of these changes we might not be able to follow the normal procedure for change managment | depends on the severity of the issue | We define a __non breaking__ change as follows. Any change to the API that does not cause failures in the applications that consume that API. * Introducing a new optional field to an existing resource * Introducing a new endpoint * Introducing a new operation (GET/PUT/POST/PATCH/DELETE) * Introducing a new optional parameter to an endpoint * Introducing a new version for a resource We define a __breaking change__ as follows. any change to an API that could potentially cause failures in the applications that consume that API. * Changing an existing JSON element (name, datatype, pattern, min/max length etc) * Removing a JSON element, endpoint, operation or parameter * Introducing a required JSON element * Introducing a required parameter to an endpoint * Passing the `obsoleteDate` of a version for a resource ## Versioning The Loket API uses two types of versioning. API versioning and resource versioning. __API versioning__ API versioning is done via the path where after the domain URL (api.loket.nl) the path starts with the API version. The current version of the API is V2. The API version is expected to change rarely as resource versioning is available to tackle most issues that need versioning. __Resource versioning__ Every __JSON__ resource in the API is versioned via the Accept header. Allowing users of the API to influence what version is returned by setting the __mandatory__ accept header. The Accept header of request should have a value like `application/json;version=2018-01-01`. Here, the second part of the header is used to refer to a specific version of the resource (2018-01-01). When calling the API it is possible to supply other dates rather than the exact resources version(s). The businesslogic will select the version that is ON or BEFORE the given date. __For example:__ let's say there are two versions of a resource. These are 2018-01-01 and 2018-09-01. When calling the API you supply `application/json;version=2018-08-01`, in that case the API will use the version 2018-01-01 as its the nearest version in the past. A response returns what `resourceVersion` was used and the 'obsoleteDate' of that version (in most cases this is NULL). The `obsoleteDate` indicates when the resources version will no longer be available via the API. With the introduction of a new version of a resource the `obsoleteDate` for the old version will be set to 6 months after the introduction of the new resource. Allowing consumers of the resource 6 months to incorporate the change. Failure to do so will likely lead to failure in the implementation. In this developer portal you can find the service contracts for each, active, version of a resource. If, only if, there are multiple versions of a resource you can select the corresponding schema at that resource. ## Changelog The changelog for this API can be found [here](/Changelog). We strongly advise every user ofthe Loket REST API the subscribe to the email feed. Please check out the link on the changelog page. ## Legal notices Your use and access to the API is expressly conditioned on your compliance with the policies and restrictions related to the API. If Loket.nl believes that you have or attempted to violate any term, condition, or the spirit of these policies or agreements, your right to access and use the API may be temporarily or permanently revoked. # Authentication Authorization in the Loket API is based on the industry-standard OAuth 2.0 protocol. For general information on OAuth 2.0 we kindly refer to the publicly-available documentation, https://oauth.net/2/ An authorized user is required to call the Loket API. __Note:__ This is an SSL-only API. __Note:__ Only TLS 1.2 is supported. | Environment | TokenUrl | | -------------------- | -------------------------------- | | Acceptance | https://oauth.loket-acc.nl/token | | Production | https://oauth.loket.nl/token | The following OAuth 2.0 flows are supported * Authorization Code flow (standard) * Refresh Token flow (extension on the Authorization Code Flow) * SSO flow (single sign-on) * Password flow ## Authorization code flow For most clients only the authorization_code (and thus refresh_token) will be supported. Password grant type is not available for an external client. Please click the link below to see documentation on implementing the authorization code flow by external clients. __[Documentation on implementing the OAuth 2.0 authorization code flow](./OauthCode)__ ## Refresh token flow After the authorization code flow yields a refresh token the refresh_token grant can be used to obtain an access/bearer token. The expire time of the access/bearer is also returned in the response please take this into account. With the refresh token flow the two factor step will be skipped. _Refresh token request example:_ ``` POST /token grant_type=refresh_token&refresh_token={RefreshToken123}&client_Id={Client123}&client_secret={Secret123} ``` _Refresh token response example:_ ```json { "access_token": "JESJDhMBy0NPTM9SiXmYAzW45clOiQ5wSyDq3VWluguGNoKym4WPSiJoTDx67TQ", "token_type": "bearer", "expires_in": 3599, "refresh_token": "nGJtF6j6SeQbHAg", "two_factor_state": "None" } ``` ## SSO flow The SSO (single sign-on) flow is based on OAuth 2.0 and requires the authorization flow to be completed. __For more information see:__ [Documentation on OAuth 2.0 SSO flow (for allowed clients)](./OauthSSO) __Please note:__ Among other things, it is possible to set up an SSO flow with both Loket en Werknemerloket. ## Password flow The password flow is typically NOT enabled for external clients. Only by exception will the password flow be enabled for security (and practical) reasons. _Password token request examples:_ ``` POST /token grant_type=password&username={UserName123}&password={Password123}&client_Id={Client123}&client_secret={Secret123} ``` Whether client_secret is required is dependent on the configuration of the client. # Authorization In this section we explain how the API authorization service determines if a request is authorized or not. ## The authorization entities | Entity | Description | | ----|----| | Client | Loket.nl used the client as an additional authorisation entity. By linking clients to activities clients can only perform those activities they are linked to. | | User | Is linked to a client (by performing the authorization code flow) and to a set of rechten (configuration in loket.nl)| | Module (product) | Enables certain functionality for the provider/employer. Modules can be enabled and disabled on both provider and employer level.| | Role | Influences if certain "rechten" are available to the users with said role. It can also influence the scope of the data returned. For example: the API will deny an "afdelings manager" access to employee's that are not in the "afdeling" (department) that user is manager of| | Activity | Every action in the API has its own activity. Using the Open API 3.0 standard these activity names are incorporated in the documentation using the `operationId` and in most cases are named in the description of an endpoint.| | Rights (rechten) | Represent a group of activities.| ## The authorization process This flow assumes that both user and client are correctly configured and have access to the API. 1. Does the client have access to the activity? 2. Does the user have access to the activity (through "recht")? 3. Does the role have access to the activity (through "recht")? 4. Does the provider/employer have the required module enabled for the activity? 5. Does the user have access to the specified entity/ID? If the answer to all the questions above is yes then the request is authorized otherwise the request is denied with a HTTP status code 403 (Forbidden). See the simplified authorization flow in the figure below. __Side note:__ users are linked to rechten and clients are linked to activities. This leaves room for discrepancies. Where a client cannot perform the activity because the client is not authorized to call that activity even though the user does have the "recht" granting access to the activity. ![Loket authorization flow](../Authorization_flow_extern.png) ## Which users can use the API In almost all use-cases a Loket user should meet the following requirements to successfully setup an integration with that user. * The user must be a normal Loket user (so NOT a webservice user) * The user must be active (not blocked) * The user must have access to an employer * For provider users this is done by assigning the user to the appropriate Team(s) * For employer users this is done by creating a user for or linking the user to the appropriate employer(s) * The user must have all appropriate rights * For provider users this is done by assigning appropriate rights via Team (or alternatively, directly to the user) * For employer users this is done by assigning appropriate rights to the user on employer level How to setup an integration is described in the [Authentication](../#section/Authentication) section. __Side notes:__ * A user can have access to multiple employers with different rights per employer. * Please note that users set up to use the SOAP webservices (webservicegebruikers) are in no way suited to perform calls to the RESTful API, these require entirely different user set-ups. * User management on production is typically done by the provider (i.e. the accountant) and sometimes the employer. This is NOT something Loket.nl itself can do. # Data ## Data types The Loket.nl API accepts and returns JSON. Comform the [OpenAPI 3.0 specification](https://github.com/OAI/OpenAPI-Specification) the following data types are supported: * string * number (point is used to separate the integer part from the fractional part of a number) * integer (from OpenAPI) * object * array * boolean For most of these types, further specifications can be found in the `format` and `pattern` specifications in the service contract. For example a `format: date` added to a string field indicates a valid date must be supplied. ## Metadata Fields of the type 'metadata' are fields for which the possible values can be acquired via the metadata endpoint of the resource. The metedata can be obtained by appending /metadata to the current endpoint. Using the GET verb the endpoint will return a JSON output with "all" the metadata for the given resource. In some cases multiple requests are needed to obtain all the metadata required, an exmple is given below. Typically different metadata endpoints are availalbe for the POST and the PUT endpoint. If metadata endpoints are avaible for a given endpoint/resource is mentioned in the description of that endpoint. ### Example response ```json {[ { "field": "gender" options: [ { "key": 1, "value":"Man" } { "key": 2, "value":"Vrouw" } ] }, { "field": "country" options: [ { "isoCode":"NL", "key": 530, "value":"Nederland" } { "isoCode":"BE", "key": 540, "value":"België" } ] } ]} ``` ### Example urls __Acquiring metadata for a POST Wage__ ``` /v2/providers/employers/employees/employments/{employmentId}/wages/metadata ``` __Acquiring metadata for a PUT employee__ ``` /v2/providers/employers/employees/{employeeId}/metadata ``` __Multiple requests to get all the metadata__ In some cases there are metadata fields dependant on the selected value off another metadata field. Such is the case when adding a new concept employee. This is done in the employer context while several of the metadata fields are dependant on the payrollAdministration context. __For example:__ __Request 1__, first of a normal metadata request is performed. The response for this request will contain a list of payrolladministration for the given employer. ``` /v2/providers/employers/b869ded6-0659-4d8d-9a8a-f9e22425ec9c/jobapplicant/metadata ``` __Request 2__, when a payrolladministration is selected perform a second request to acquire the payrolladministration specific metadata. ``` /v2/providers/employers/jobapplicant/metadata/payrolladministration/54369214-14a1-41ab-892a-ea8438e34d6f ``` __Request 3__, if a `payScale` is selected perform a third request to acquire the `payGrade` for that `payScale`. ``` /v2/providers/employers/jobapplicant/metadata/salaryScaleType/54369214-14a1-41ab-892a-ea8438e34d6f ``` ### Types of metadata We diferentiate between two types of metadata. 1. Generic metadata field. The possible values for these fields are the same for every object no matter the provider, employer or employee etc. Examples are: country, gender and nationality. 2. Context specific metadata field. Examples of contexts are employer, payroll administration, provider and Loket.nl. In most cases the possible values for these field are resources in themselves and can be managed via the API. If a metadata field is context specific the context is given in the description of the field. Examples are: function, department and leaveType. __Note:__ some context specific metadata field can have multiple contexts. For example: it is possible to define an export set in the provider context. Making that export set available for all payroll administrations linked to the provider. It is also possible to add an export set in the payroll administration context. That export set is only available to that payroll administration. When requesting the metadata of export set the user will be presented with a combined list of the provider and payroll administration export sets. ## Default values Many fields in the API have a default value. In order to assist our API users to adhere to these defaults when creating a record (POST) we provide `/defaults` endpoints. * An object returned by the `defaults`endpoint resembles a fully expanded GET-object of that resource. The only case when a part of the object is NOT fully expanded is for a metaData-object that does not have a default value (for example '"gender":NULL'). * Whether an object within the resource is of the type metaData is indicated in the service contracts of that resource. * Context is determined by the GUID given in the Path. Examples are employer, payroll administration, employee and employment. * A scope is sometimes required to determine the defaults values. A scope could be a date by which Loket.nl can determine what default was active on that date. The scope can be set by supplying additional paraments in the request. If a scope is required but none is given the currently active or last know value is returned. * The fields with no default will be set to null (even if the field is normally non-nullable). * Because the GET-object is returned the readonly fields are also returned. __An example endpoint would be:__ ``` /v2/providers/employers/employees/employments/{employmentId}/payrollperioddata/defaults ``` __resulting in the following output:__ ```json { "payrollPeriod": null, "shift": { "shiftNumber": 1 }, "payslipType": { "key": 2 }, "payslipText": null, "distributionUnit": { "key": "b14acd0d-75d7-4fc8-8b22-4a3924585cab" }, "costCenter": { "key": 2 }, "costUnit": { "key": 2 }, "payrollComponents": [] } ``` __Note: Defaults endpoints are not yet generically available. If a Defaults endpoint exists this will be explicitly stated at that specific resource.__ ## Date chains For most of the resources with a startDate and endDate a chain is maintained. Chain meaning that no records can overlap in time. Loket.nl has two types of chains. 1) __Broken chain:__ It is posible for gaps te exist between the records. It is also posible to add new records in between or before existing records aslong as no overlap occures. 2) __Linked chain:__ No gaps between records are allowed. Its only posible to add new records to the end of the chain resulting in the closing of the reviouse record with the start date -1 as end date. __Note:__ Chains are sometimes maintained with an additional context. For example, For `benefits and deductions` the broken chain is maintained per `payrollComponent`. It is possible to have multiple active records for different `payrollComponent` never two active records for the same `payrollComponent`. ## Custom export For some GET (list) endpoints the API supports exporting (part of) the output JSON as a XML/CSV file. This is done by setting the `X-ReportInput` and `Accept` header. The `Accept` header supports the following 2 options: * CSV (text/csv;version=yyyy-MM-dd) * Excel (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;version=yyyy-MM-dd) The `X-ReportInput` is a custom header that requires a JSON object with the following structure as input. The filename without extension for the report 'FileNameWithoutExtension' delimiter --> The delimiter to be used. If not set "," is used Array of objects 'fields' with 2 fields: 1. fieldName --> A Xpath reference to the field to be included in the export 2. reportColumnName --> The column name for the field 3. format --> Allows only for date formatting. e.g. dd-MM-yyyy for csv or dd-mm-yyyy for Excel (Excel only usses lowercase) 3.1 For CSV: see https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings 3.2 For Excel: https://support.microsoft.com/en-us/office/number-format-codes-5026bbd6-04bc-48cd-bf33-80f18b4eae68 __Example `X-ReportInput`:__ ```json { "fileNameWithoutExtension":"MyExport", "delimiter": ";", "fields": [ { "fieldName": "startDate", "reportColumnName": "In dienst datum", "format": "dd-MM-yyyy" }, { "fieldName": "personalDetails.firstName", "reportColumnName": "First Name" }, { "fieldName": "personalDetails.lastName", "reportColumnName": "Last Name" } ] } ``` __Example request:__ ```CURL curl --location --request GET 'https://api.loket.nl/v2/providers/employers/155c8440-8ff6-4776-98db-5d2243a073e3/employees?orderby=employeeNumber' \ --header 'Content-Type: application/json' \ --header 'Accept: text/csv;version=2020-08-18' \ --header 'X-ReportInput: {"FileNameWithoutExtension":"MyExport","Fields":[{"fieldName":"personalDetails.initials","reportColumnName":"Initials"},{"fieldName":"personalDetails.firstName","reportColumnName":"First name"},{"fieldName":"personalDetails.lastName","reportColumnName":"Last name"}]}' \--header 'Authorization: Bearer ZKoiC_g_NfYA3v0' \ ``` # Request A request to the Loket.nl API consists of several components. Each of these components are discussed in this section. ## Base URL The API can be accessed at [https://api.loket.nl](https://api.loket.nl). The version of the API is specified in the URL. The current version of the Loket.nl API is version 2. To access version 2 of the API, one simply appends `v2` to the base URL. The full base URL of the API is therefore [https://api.loket.nl/v2](https://api.loket.nl/v2). ## Endpoints The endpoints defined in the OpenAPI definition of the Loket.nl API are appended to the base URL. For example, the endpoint `/providers/employers/{employerId}/employees` can be accessed at [https://api.loket.nl/v2/providers/employers/{employerId}/employees](https://api.loket.nl/v2/providers/employers/{employerId}/employees). ## Path parameters Most endpoints require path parameter(s) in order to specify the context of the request. For example, the endpoint `/providers/employers/{employerId}/employees` contains the `employerId` path parameter. A path parameter is a unique identifier that identifies a specific resource, in this case an employer. ## Pagination The API supports two query parameters to control the pagination of the results: `pageNumber` and `pageSize`. Both of these query parameters only apply to endpoints that return lists of entities. The `pageNumber` query parameter specifies which page of the collection to return. By default `pageNumber` is set to 1 which returns the first page of the collection. Note: the pageNumber refers to the page (with a given number of entities), NOT to a specific entity within a page! The `pageSize` query parameter influences the number of entities per page. By default `pageSize` is set to 250. Note that this default may change in the future. It is not recommended to depend on this default when developing for the Loket.nl API. Examples: * ```?pageNumber=2``` to return the second page * ```?pageSize=2``` to set the page size to two ## Filtering The API supports output filtering via the querystring parameter `filter`. Filtering is possible on all fields of the following datatypes: * string * integer * boolean * date-time * decimals The following operators are available: | Operator | Description | Example | | -------------------- | --------------------- | ------------------------------- | | Comparison Operators | | | | eq | Equal | `city eq 'Redmond'` | | ne | Not equal | `city ne 'London'` | | lk | Like | `city lk 'Lond'` | | gt | Greater than | `price gt 20` | | ge | Greater than or equal | `price ge 10` | | lt | Less than | `price lt 20` | | le | Less than or equal | `price le 100` | | Logical Operators | | | | and | Logical and | `price le 200 and price gt 3.5` | | or | Logical or | `price le 3.5 or price gt 200` | Both field names and values are case insensitive. It is possible to filter on nested fields by adding the parent object before the field with a '.' to separate them. Do remember to URL encode the filter parameters. ### Examples All employments with a cancellation periode in months (the value 4 corresponds to months time unit). ``` /v2/providers/employers/{{employerId}}/employees/employments?filter=cancellationPeriodTimeUnit.key eq 4 ``` All employments with no endDate.s ``` /v2/providers/employers/{{employerId}}/employees/employments?filter=enddate eq null ``` All employments with an end date less or equal to 2017-01-01 ``` /v2/providers/employers/{{employerId}}/employees/employments?filter=enddate le '2017-01-01' ``` All employees with a employee number greater or equal 1 and less or equal 5 ``` /v2/providers/employers/{{employerId}}/employees?filter=employeeNumber ge 1 and employeeNumber le 5 ``` ## Ordering All Loket.nl API resources support ordering of the elements in the response on a specific field. All fields can be used in ordering. The list can be ordered in ascending or descending order, with ascending being the default one. Ordering on multiple fields is also by using a ',' as a separator. ### Examples Order employers by company name ascending ``` /v2/providers/employers?orderBy=companyName ``` Order employers by company name descending ``` /v2/providers/employers?orderBy=-companyName ``` Order employers by company name descending then by house number ascending ``` /v2/providers/employers?orderBy=-companyName,address.houseNumber ``` ## Headers In order to access the endpoints of the Loket.nl API, at least two request headers need to be set. __1)__ the `Authorization` header is required in order to authorize the API call. The value of this header is the word Bearer followed by a space and the access token acquired from the `/token` endpoint. For example, if the acquired access token is `AbCdEf123456`, the value of the `Authorization` headers would be: ``` Authorization: Bearer v69uloc3wcEFLePw2unot0FfAJfBocrvSwsrCo75JLUG7aE54zqSUnU ``` __2)__ The second header that is required for proper usage of the API, is the `Accept` header. This header is used for the resource versioning feature and is therefore crucial for making sure the response remains the same when new resource versions are introduced. The value of the `Accept` header differs per endpoint is defined in the OpenAPI documentation of the endpoints. ``` Accept: application/json;version=2018-01-01 ``` __3)__ In case of a PUT and sometimes a PATCH a third header is optional the if-match header. This header is used for concurrency control. Even though the header is optional we advise using this header on every PUT(PATCH) to ensure not losing data. ``` if-Match: aslkhas987da09s8udasd09a ``` # Response In addition to the responses defined in the OpenAPI documentation, the Loket.nl API also provides additional fields that give more information about the response and the entities requested. This section will explain the full response given by the Loket.nl API by examining the example response below. Example 400 response ```json { "version": { "obsoleteDate": null, "versionNumber": "2018-01-01, }, "messages": [ { "code": 83, "id": null, "type": "BrokenBusinessRule", "description": "[field] has an invalid length", "properties": [] } ], "_embedded": [] } ``` Example 200 response ```json { "totalSize": 1, "pageSize": 250, "totalPages": 1, "currentPage": 1, "version": { "obsoleteDate": null, "resourceVersion": "2018-01-01" }, "messages": [], "content": { "id": "2b4c119c-527c-4cbb-a5b2-f3a11e4b76cx", ... } } ``` ## Paging * `totalSize` has an integer value indicating the total number of entities irrespective of the page size. * `pageSize` has an integer value indicating the maximum number of entities returned per page. The page size can be influenced by setting the `pageSize` query parameter. See the section Query Parameters for more information. * `totalPages` has an integer value indicating the number of pages the requested collection holds given the specific pagesize. * `currentPage` has an integer value indicating the current page number. The current page number can be influenced by setting the `pageNumber` query parameter. See the section Query Parameters for more information. ## Version The `version` object provides information regarding the resource version of the entity requested. * `obsoleteDate` contains the date of discontinuation for the requested resource version. The value of this field can be `null` indicating that the requested resource version is not planned to be obsoleted at the time of the request. * `resourceVersion` shows the version of the requested entity. The resource version can be influenced by setting the `Accept` header. ## Messages The `messages` field contains a list of message objects related to the request made. Any warnings and errors will be communicated in this list of messages * `type` has a string value indicating the type of message. At this time the Loket.nl API supports five types of messages: `BrokenBusinessRule`, `Warning`, `Exception`, `ConcurrencyViolation` and `NotFound` . * `description` has a string value that describes the message that has occurred. * `code` is an identifying code for the message. Please note that this code may change in the future. See the documentation portal for possible message codes for an endpoint. * `id` relates the message to a specific entity in the reponse list. For example, in cases where a warning occurs for one of the entities in a list, the value of this field can be used to identify to which entity the warning applies. Currently implemented for endpoints where a multi-patch is performed (multiple actions are performed within one call) for example updating the status of one or more leaveRequests. * `properties` an array that can contain additional information regarding the message. Currently not yet fully implemented. * `_embedded` contains the list of entities as defined for each endpoint in the OpenAPI documentation. Please refer to that documentation for the contents of the `_embedded` field for each endpoint. For endpoints that return only one entity (detail endpoints) the `_embedded` field is replaced with a `content` field. The content of this field can also be found in the documentation for each endpoint. ## Headers * `etag` header is returned with every GET of a detail (single resource). This header is used for concurrency controle * `Expires` header is returned with every response to indicate how long a response can be cached * `Content-Disposition` header is used in case of downloads to provide a file name ## HTTP status codes The Loket.nl API supports the following http status codes. | Code | Is returned when | |------------------|---------------| | 200 | The request to GET, PUT, PATCH or DELETE and object was recived and processed succesfully. The response might still contain messages of the type warning. | | 201 | The request to insert (POST) a new object was recived and processed succesfully. The response might still contain messages of the type warning.| | 400 | The request was received but could not be processed. The reason(s) will be given in the response. The content type of the response may be text/plain for API-level error messages, such as when trying to call the API without SSL otherwise the content will be application/json. | | 401 | The bearer token provided in the authorization header is invalid. Do not retry the request until a new (valid) bearer token is acquired. | | 403 | The user is not authorized to access the resource. The reason will be given in the response. Do not retry the request until the, configuration, issue is resolved. | | 404 | The resource requested was not found/does not exist. | | 409 | The give if-match header in a PUT request no longer represents the current state of the object. Please acquire the current state off the object, via a GET, and resolve the differences then try again. | | 50* | A unforseen error occurred. Please check the request if everything seems te be in order on your side contact the support team. Provide as much information as possible to resolve the issue. | Note: for a limited number of endpoint a so-called multi-patch may be performed (multiple actions within one call). In that case the status code will be 200 if at least on of the actions succeeds, if other any action(s) in that call fail(s) a message will be returned including the given id of that entity. ## Caching The API uses the `Expires` header to indicate how long the item can be reused from the local cache. In most cases caching is not allowed for resources. Exceptions excist, such as pictures like the employer logo and the employee photo, in these cases the cache duration is mentioned in the description of the resource.
# Introduction
The Lumminary API was built to allow third parties to interact with Lumminary customers and gain access to their genetic data. The Lumminary API is fast, scalable and highly secure. All requests to the Lumminary API take place over SSL, which means all communication of Customer data is encrypted.
Before we dive in, some definitions. This is what we mean by:
|Term|Definition|
|-----------|-----------|
|**Third party**|A third party (also referred to as "partner" or as "you") is a company which offers services and products using genetic data.|
|**Lumminary clients**|The Lumminary client (also referred to as "customer") is an individual who has created an account on the Lumminary platform.|
|**Lumminary**|This is us - our services including the Lumminary platform, the API, the DNA App Store, the DNA Vault, the "Connect with Lumminary" button, and the website in its totality. |
|**CWL**|This is the acronym for the "Connect with Lumminary" button.|
|**dataset**|This is the term we use when we refer to a customer's genetic data.|
|**Lumminary API**|This is a library/module that you can use to integrate your apps with the Lumminary platform.|
|**Lumminary toolkit**|This is a stand alone application which helps you integrate with Lumminary without writing any code or interacting with the Lumminary API.|
Let's dive in, now.
* [**Overview**](#section/Introduction/Overview)
* [**Install Lumminary API Client and Toolkit**](#Install-Lumminary-API-Client-andor-Toolkit)
* [**Obtaining credentials**](#Obtaining-credentials)
* [**Query customers authorizations**](#Query-customers-authorizations)
* [**Query customer genetic data**](#Query-customer-genetic-data)
* [**Submit reports**](#Submit-reports)
* [**"Connect with Lumminary" button**](#the-connect-with-lumminary-button)
* [**API specs**](#tag/Lumminary)
## Overview
In order to use Lumminary services, you'll need to install the Lumminary API Client or Toolkit. The Lumminary API Client and Toolkit are available in multiple programming languages, and we also provide a sandbox environment which you can use for integration and tests.
There are a couple of differences between the API Client and the Toolkit. Mainly, it's about the ease of use for integration. The Toolkit is basically a stand-alone application that facilitates the integration with the Lumminary API without the need to modify your already existing code.
You use the Lumminary API Client when you want to integrate it inside your own application. This means it gives you full flexibility regarding the integration into your own workflow.
You use the Lumminary Toolkit for an integration where the Toolkit is placed alongside your own application. You can use the Toolkit from the CLI - for example, to run a cronjob that processes incoming orders. The Toolkit uses the Lumminary API Client.
# Install Lumminary API Client and/or Toolkit
We provide the Lumminary API Client and Toolkit in multiple programming languages - default are PHP (minimum version 7.0), Python2.7 and Python3. However, if you need them in another language (Java, Obj-C, JavaScript, C#, Perl, CURL), please contact us.
## How to install the Lumminary API Client
#### PHP example:
The PHP Lumminary API Client is available at: https://github.com/Lumminary/lumminary-api-client-php
If you are already using [Composer](https://getcomposer.org), you can import the project by adding the following to your `composer.json`
```json
"repositories": [
{
"type": "git",
"url": "https://github.com/Lumminary/lumminary-api-client-php.git",
"reference": "master"
}
],
"require": {
"lumminary/api-client-php": "v1.0.6"
}
```
Then run `composer update lumminary/api-client-php`
#### Python example:
The Python Lumminary API Client is available at: https://github.com/Lumminary/lumminary-api-client-python
To install directly, run
```bash
pip install git+https://git@github.com/Lumminary/lumminary-api-client-python.git@v1.0.7#egg=lumminary-api-client
```
Or add the following line in your requirements.txt
```bash
git+https://git@github.com/Lumminary/lumminary-api-client-python.git@v1.0.7#egg=lumminary-api-client
```
## How to install the Lumminary Toolkit
#### PHP example:
The PHP Lumminary Toolkit is available at: https://github.com/Lumminary/lumminary-toolkit-php
To install the Lumminary Toolkit, run the following command where 'lumminary-toolkit-directory' is the directory where you want to install the Lumminary Toolkit:
`git clone git@github.com:Lumminary/lumminary-toolkit-php.git lumminary-toolkit-directory`
#### PYTHON example:
The Python Lumminary Toolkit is available at: https://github.com/Lumminary/lumminary-toolkit-python
To install the Lumminary Toolkit, run the following command where 'lumminary-toolkit-directory' is the directory where you want to install the Lumminary Toolkit:
```bash
git clone git@github.com:Lumminary/lumminary-toolkit-python.git lumminary-toolkit-directory
cd lumminary-toolkit-directory
virtualenv env
source env/bin/activate
pip install -r requirements.txt
```
Note that before running the toolkit, you should have the virtualenv enabled, like so : `source lumminary-toolkit-directory/env/bin/activate`
## Toolkit Setup
We recommend to run the Toolkit in a cronjob; at every run it will check for new Authorizations (Orders) and will download them; afterwards it will check for a new reports folder inside the old authorizations, process the reports, and delete the processed Authorizations and Reports from your server.
The first step after you clone the Lumminary Toolkit project for your language is to configure it with your credentials.
Go to the Lumminary Toolkit base diretory `cd lumminary-toolkit-directory`. Under the Toolkit directory, you will find a file `config/config_template.json` which has the following structure:
```json
{
"api_key":
You can obtain it from the Lumminary Admin |
| product_uuid | `"1234-1234-1234-1234"` |Your product UUID. This value can be obtained from the Lumminary Admin |
| api_host | `"https:\/\/api.lumminary.com\/v1"` | The API endpoint to use.
For the sandbox environment you can use "https:\/\/sandbox-api.lumminary.com\/v1" |
| output_root | `"/var/lumminary-orders/product1/"` | The base directory where the Toolkit places the Authorizations for your Product
The Lumminary Toolkit will *never* overwrite Authorization data or create this directory, to protect from overwrites or typos |
| export_handler |`"export_handler_tsv"` | If you have a custom export handler, then your Lumminary contact will provide you with the name of your export handler. |
| operations |`["pull_datasets", "push_reports"]` | These are two optional parameters that define the tasks that the Toolkit should perform. Possible values are:
1. `pull_datasets` - this tells the Toolkit to download the Customer Authorization (Customer details and genetic data)
2. `push_reports` - this tells the Toolkit to push the results to the API; see below for more details|
| optional | `{}` | Export handler specific value |
After updating the config file for your Toolkit, it should look similar to (Note that these are all dummy values) :
```json
{
"api_key": "TiiU...bqg==",
"product_uuid": "1234-1234-1234-1234",
"api_host": "https:\/\/api.lumminary.com\/v1",
"output_root": "\/var\/lumminary-orders\/product1\/",
"export_handler": "export_handler_tsv",
"product_name": "product 1",
"operations": [
"pull_datasets",
"push_reports"
],
"optional": {
"dna_data_filename": "dna-data.tsv",
"authorization_metadata_filename": "authorization-metadata.json"
}
}
```
You can now save and exit the text editor `:wq` and start polling the API for new Authorizations :
Python
```bash
# While still in the
`{ "credentials": { "username": "username@example.com", "password": "your generated password", "url": "https://your-website.com/report"}}`
The `url` should point to a login page that upon authentication redirects the user to the report page. You can find the customer's email address in the `authorization-metadata.json` and the `password` attribute must be a secure password. Please refer to the Note underneath this table. |
|The product is a physical product| Create a file with the name `result.json` into the `tmp_reports` directory, with the following content:
`{"physical_product": { "physical_product_completed": true }}`
This should be done upon dispatch. Please refer to the Note underneath this table. |
|An error occurred| Create a file with the name `result.json` into the `tmp_reports` directory, with the following content:
`{ "unfulfillable": {"error": "Reasons for why it is unfulfillable", }}`
The error message is for Lumminary internal usage, and it won't be visible to the customer. This will delete your Authorization, making it unuseable thereafter. So please use this only for unfixable errors, and never for temporary errors you attempt to resolve. Please refer to the Note underneath this table. |
###### Note
For each scenario above, we recommend you use a temporary directory to avoid uploading incomplete files or reports. So your workflow should be:
* create a temporary directory inside the `
This impacts the reference allele, location, and based on the dbSNP build, also the SNP's accession |
| `genotypedAlleles` | `genotyped_alleles` | The genotype value of the customer's queried SNP.
If the attribute of this SNP has the `phased` flag set to True,
the first items in the lists for all SNPs will be on the same inherited chromosome,
and analogous for the second item.
If the SNP is unphased, the order of the items is irrelevant |
|`phased` | `phased` | A boolean. True if the SNP is known to be phased, False otherwise |
|`chromosomeAccession` | `chromosome_accession` | This is the chromosome accession number where the SNP is located; in the format of NC_00x |
|`location` | `location` | This is the customer's SNP's location on the chromosome |
When trying to access any customer's SNP for which you don't have permission, an `Unauthorized` exception will be raised.
## Get all authorized SNPs
The function below returns all SNPs your product has access to. These are all the SNPs configured as mandatory for your product, as well as all SNPs that are configured as optional and available in the customer's data set. We encourage you to use this option if you need to get all available SNPs, because it is faster than fetching SNP details one by one.
For example, fetching all authorized SNPs:
#### PHP example:
```php
$datasetSnps = null;
// check to see if you have access to the customer genetic data
if (isset($productAuthorization["scopes"]["dataset"]))
{
// get all authorized SNPs
$datasetSnps = $apiClient->getClientSnpGroup(
$productAuthorization["clientUuid"],
$productAuthorization["scopes"]["dataset"]
);
}
```
#### Python example:
```python
datasetSnps = None
# check to see if you have access to the customer genetic data
if hasattr(productAuthorization.scopes, "dataset"):
# get all authorized SNPs
datasetSnps = apiClient.get_client_snp_group(
productAuthorization.client_uuid,
productAuthorization.scopes.dataset
)
```
##### The datasetSnps variable will be a list of objects each having the following attributes:
| Attribute name PHP | Attribute name Python | Description |
|:-------------------------:|:-------------------------:|:----------------------------------------------------------|
| `snpId` | `snp_id` | The rsid of the SNP |
| `referenceGenome` |`reference_genome` | The reference genome known to be used by the Dataset's source.
This impacts the reference allele, location, and based on the dbSNP build, also the SNP's accession |
| `genotypedAlleles` | `genotyped_alleles` | The genotype value of the customer's queried SNP.
If the attribute of this SNP has the `phased` flag set to True,
the first items in the lists for all SNPs will be on the same inherited chromosome,
and analogous for the second item.
If the SNP is unphased, the order of the items is irrelevant |
|`phased` | `phased` | A boolean. True if the SNP is known to be phased, False otherwise |
|`chromosomeAccession` | `chromosome_accession` | This is the chromosome accession number where the SNP is located; in the format of NC_00x |
|`location` | `location` | This is the customer's SNP's location on the chromosome |
When trying to access any customer's SNP for which you don't have permission, an `Unauthorized` exception will be raised.
## Get Genes
Along with individual SNPs, you can also get all the authorized SNPs from a particular gene, that are available in the customer's dataset.
Here, by genes, we refer strictly to the genomic region that produces some protein, without considering regulatory or noncoding regions that influence gene expression.
The gene name (known as symbol) can be from either of these two databases - NCBI and Ensembl.
For example, fetching details for a gene symbol:
#### PHP example
```php
$geneSymbol = "C1ORF159";
$geneDetails = null;
// check to see if you have access to the customer genetic data
if (isset($productAuthorization["scopes"]["dataset"]))
{
// get all authorized SNPs within a gene
$geneDetails = $apiClient->getClientGene(
$productAuthorization["clientUuid"],
$productAuthorization["scopes"]["dataset"],
$geneSymbol
);
}
```
#### Python example
```python
geneSymbol = "C1ORF159"
geneDetails = None
# check to see if you have access to the customer genetic data
if hasattr(productAuthorization.scopes, "dataset"):
# get all authorized SNPs within a gene
geneDetails = apiClient.get_client_gene(
productAuthorization.client_uuid,
productAuthorization.scopes.dataset,
geneSymbol
)
```
##### All the geneDetails object attributes are
| Attribute name PHP | Attribute name Python | Description |
|:---------------------:|:---------------------:|:-----------------------------------------------------------------------------------------|
| `molecularLocation` | `molecular_location` | An object containing the location of the gene within the chromosome - see below the molecular location object structure |
| `snps` | `snps` | A list of SNP objects present in the gene - see below the SNP object structure |
| `symbol` | `symbol` | The gene's accession string (name) |
##### Molecular location attributes
| Attribute name PHP | Attribute name Python | Description |
|:-------------------------:|:---------------------:|:-----------------------------------------------------------------------------------------|
| `chromosomeAccession` | `chromosome_accession` | The scaffold/chromosome on which the gene is placed |
| `start` | `start` | The gene's start position on the scaffold |
| `stop` | `stop` | The gene's stop position on the scaffold |
##### SNP object structure
| Attribute name PHP | Attribute name Python | Description |
|:-------------------------:|:---------------------:|:-----------------------------------------------------------------------------------------|
| `referenceGenome` | `reference_genome` | The reference genome known to be used by the Dataset's source.
This impacts the reference allele, location, and based on the dbSNP build, also the SNP's accession|
| `genotypedAlleles` | `genotyped_alleles` | The genotype value of the customer's queried SNP.
If the attribute of this SNP has the `phased` flag set to True,
the first items in the lists for all SNPs will be on the same inherited chromosome,
and analogous for the second item.
If the SNP is unphased, the order of the items is irrelevant |
| `phased` | `phased` | A boolean. True if the SNP is known to be phased, False otherwise |
| `chromosomeAccession` | `chromosome_accession` | This is the chromosome accession number where the SNP is located; in the format of NC_00x |
| `location` | `location` | This is the customer's SNP's location on the chromosome |
## Get customer genetic data in 23andMe tsv format
If your platform is already compatible with 23andMe genotype data files, you can use this specific function to generate data in the 23andMe format - list of rows in tab separated values.
#### PHP example:
```PHP
$authorizationDnaData = $apiClient->authorizationDnaData($productAuthorization["authorizationUuid"]);
```
#### Python example
```python
authorizationDnaData = apiClient.authorization_dna_data(productAuthorization.authorization_uuid)
```
`authorizationDnaData` contains a list of rows in a tsv (tab delimited values)/csv format (23andme-compatible)
# Submit reports
After you finish analysing the customer's genetic data, we need to inform the customer their analysis is complete. To do this, you will notify us using the function below. Finally, the customer will then:
* access their report file through a written electronic document (eg. .pdf or .doc)
* access their report on your website under an account with a username and a password or
* receive a physical product
## How to submit a report file
When you submit such a report file, Lumminary will save this document into the customer's account, from which the customer will then be able to access it directly.
#### PHP example
```php
$pathToReportFile =
```html
```
##### b. Black button version
```html
```
## Button configuration
Each button has 2 attributes which need to be configured:
1. **data-partner-uuid** where you have to add your partner UUID (you have received the partner UUID after filling in the form for product registration).
2. **data-request** which is a string obtained by encrypting a serialized JSON (you have received the CWL encryption key after filling in the form for product registration). See details below.
#### Data-request object
The data-request object has a standard format which needs to be preserved. It is formed of two types of data, some mandatory and some optional. You can use the optional fields to add any metadata or other information for your own use. The data-request object is going to be returned with the response from the authentication without being altered.
##### Mandatory information
The mandatory information is a list of scopes which you ask the client to grant permission for. These scopes are comma delimited, and the possible options are: `address`, `email`, `dataset`.
The scopes _address_, _email_, and _dataset_ can be used in any combination; you must request at least one scope.
| Attribute name | Description |
|:-----------------:|:----------------------------------------------------|
| `address` | Requests access to a customer's name and address. |
| `email` | Requests access to a customer's email address. |
| `dataset` | Requests access to a customer's genetic data |
#### PHP example:
```php
$objAuthorizationRequest ["scopes"] = "address,dataset,email";
```
#### Python example:
```python
objAuthorizationRequest ["scopes"] = "address,dataset,email"
```
Product UUID is your `productUuid` for which you ask customer permissions.
#### PHP example:
```php
$objAuthorizationRequest["productUuid"] = $credentials->getProductUuid();
```
#### Python example:
```python
objAuthorizationRequest["productUuid"] = credentials.product_uuid
```
##### Optional information
In the optional part of the object, you can add any useful data, such as customer ID, session ID, or any parameter which can help you identify the response from Lumminary.
#### PHP example:
```php
$objAuthorizationRequest["customData"] = array();
$objAuthorizationRequest["customData"]["customerId"] =