{"activeVersionTag":"latest","latestAvailableVersionTag":"latest","collection":{"info":{"_postman_id":"c5b65ac5-9492-46ec-a168-24e5263548d0","name":"Data Ingestion API","description":"This documentation is about RAIN’s Data Ingestion API which allows clients to securely send Eligible Employees (EE) and Timekeeping (TK) data to RAIN's system.\n\nHR, Payroll, and Timekeeping providers that want to integrate with RAIN’s platform to provide Earned Wage Access (EWA) capabilities to their users can push EE and TK data to Rain via this API. Providers can also push data via CSV or API connector, though this documentation exclusively covers integration with RAIN's Data Ingestion API.\n\nThe audience of this documentation is Backend and QA engineers from RAIN’s partners that will work on the integration, which entails getting Eligible Employee and Timekeeping data from their system and sending it to RAIN through this API.\n\nAll the ingestion endpoints work asynchronously. This means that our system will process the submitted data in the background and send the processing status via webhooks.\n\nThe high level view of the API can be seem in the diagram below:\n\n<img src=\"https://lucid.app/publicSegments/view/c5a7d386-bd45-49fd-a7a2-761561ddf6df/image.png\">\n\n**Figure 1: Authentication overview diagram**\n\n<img src=\"https://lucid.app/publicSegments/view/26272112-0083-4464-978d-31985b4229ab/image.png\">\n\n**Figure 2: Ingestion overview diagram**\n\n## Environment\n\nThe RAIN's Workspace with the Data Ingestion API Collection is available [here](https://www.postman.com/rain-app/workspace/rain-s-workspace/collection/19628595-c5b65ac5-9492-46ec-a168-24e5263548d0?ctx=documentation).\n\nThis Collection includes a pre-configured environment. You will need to set up the following variables in order to run each request:\n\n| **Name** | **Description** |\n| --- | --- |\n| `client_id` | _client id_ provided by RAIN |\n| `client_secret` | _client secret_ provided by RAIN |\n| `scope` | _scope_ provided by RAIN |\n| `api_url` | URL for the desired environment |\n| `x_api_key` | _API Key_ provided by RAIN |\n| `access_token` | Generated by requesting POST _/v1/oauth2/token_ |\n\n# 1\\. Key API Concepts\n\n# 1.1. Glossary of Terms\n\n| **Term** | **Definition** |\n| --- | --- |\n| Earned Wage | Amount in USD earned by the employee calculated cumulatively until a specific date, according to the hours worked. E.g. an employee that earns $20/hour, after working 2 days of 8 hours each has an Earned Wage of 2x8x20 = 320 USD. |\n| Group code | Code used to group employees in locations or roles. |\n| Pay cycle | Start/end date for the period that the employee is paid. E.g. for a weekly pay cycle, the pay cycle can start on a Sunday and end on a Saturday. |\n| EE | Eligible Employee |\n| TK | Timekeeping of an employee |\n\n# 1.2. Data Flow Diagram\n\nThe following are high level diagrams that show the data ingestion flow:\n\n### Employer Ingestion\n\n<img src=\"https://lucid.app/publicSegments/view/18f9d7f1-a527-49a4-9fbc-26092159c686/image.png\">\n\n### Employee Ingestion\n\n<img src=\"https://lucid.app/publicSegments/view/0d154dfb-cb7f-414d-959a-504b0176d806/image.png\">\n\n### Timekeeping Ingestion\n\n<img src=\"https://lucid.app/publicSegments/view/465e060c-cd38-41bb-97f4-ab21e227bf33/image.png\">\n\n# 1.3. Security Overview\n\nTo provide safe and secure access to RAIN's API endpoints, TLS connections and mTLS authentication are required. All the endpoints also require an API key and OAuth2 authentication. This means that in order to use the Data Ingestion API, RAIN must grant credentials, keys, and certificates to the partner in advance.\n\n<img src=\"https://www.cloudflare.com/resources/images/slt3lc6tev37/5SjaQfZzDLEGqyzFkA0AA4/d227a26bbd7bc6d24363e9b9aaabef55/how_mtls_works-what_is_mutual_tls.png\">\n\nReference: [<i>What is mutual TLS (mTLS)?</i>](https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/)\n\n# 1.4. Development Process and Environments\n\nRAIN provides a `sandbox environment` to be used by the client to validate the development and integration with RAIN's system.  \nThis environment has settings similar to the `production environment`, which will be provided to the integrator after validation in the `sandbox environment` is completed.\n\n# 2\\. Getting Started\n\nThis section is a list of practical guides on how to use our API including onboarding, authentication and using the main endpoints.\n\nTo start using our API, you first need to get access to:\n\n\\* API credentials and certificates  \n\\* Sandbox environment URL\n\nIn order for RAIN to provide access to the API, here is **what you will need to provide to your RAIN technical contact:**\n\n1. URL of the webhook (REST) where the processing events will be sent.\n    \n2. API key to access the URL of the webhook.\n    \n3. PGP key pair. Send the public key to RAIN so the certificate can be shared.\n    \n\nHere are the specific items that **your RAIN technical contact will provide you**:\n\n1. Sandbox environment URL.\n    \n2. TLS certificate with annual renewal, sent encrypted with the PGP key pair.\n    \n3. API key.\n    \n4. Client ID and client secret, for **OAuth2** authentication.\n    \n\n<img src=\"https://lucid.app/publicSegments/view/2c7317a5-f6fb-4ca0-bb02-0652e3e8dd27/image.png\">\n\n**Figure 3: Items exchange diagram**\n\n# 2.1. Certificate Management\n\nThe standard **certificate duration we use is 1 year.** Below is the explanation of how to obtain the certificate on different occasions.\n\n### Requesting the First Certificate\n\nThe first certificate will be sent manually and will be encrypted using the PGP public key provided to RAIN, as explained in the [Section 2](#2-getting-started) above.\n\n### Renewing Certificate\n\nFrom the second certificate onwards, RAIN will send the new certificate using a webhook event. Below you can see an example of the payload:\n\n``` json\n{\n  \"type\": \"CERTIFICATE_RENEWAL\",\n  \"body\": {\n    \"download_link_key\": \"https://url-download.com/client.key.gpg\",\n    \"download_link_pem\": \"https://url-download.com/client.pem.gpg\"\n  }\n}\n\n ```\n\nCheck the _Topic Certificate Renewal Event_ for more details.\n\n# 2.2. Submitting Employer Data\n\n## Employer ingestion\n\nTo submit employer data to RAIN's Data Ingestion API, the client will need to use the [Employer Ingestion endpoint](#99d7d41e-8f1d-4c51-973b-b7d8ecb7a4f8).\n\nThis endpoint allows clients to submit one single employer data per request. The response of each request will contain the result if the employer has been processed by RAIN's system.\n\n**The client should submit all the employers before start sending the employees to be ingested.** The field `employer_code` will be used to link an employer to its employees.\n\n## Employer retrieval\n\nTo retrieve employers ingested by RAIN's Data Ingestion API, the client will need to use the [Employer retrieval endpoint](#f6945fe9-299e-472c-9a7d-10cf7ff8c1d5).\n\nThis endpoint allows clients to get all or one single employer per request. The response of each request will be a list containing the employers data ingested by RAIN's system.\n\n## Employer update\n\nTo update an employer ingested by RAIN's Data Ingestion API, the client will need to use the [Employer update endpoint](#0d8ded45-e332-405a-acef-2d513b7ea575).\n\nThis endpoint allows clients to update an employer `name` and `status` per request. The response of each request will contain the result if the employer has been updated by RAIN's system.\n\n**Remember to update the employer** **`status`** **to** **`ACTIVE`** **once it's ready to be listed to its employees on RAIN's system.**\n\n# 2.3. Submitting Employee Data\n\nTo submit employee data to RAIN's Data Ingestion API, the client will need to use the [Employees Ingestion endpoint](#bc00be52-1962-4254-a071-459e68548111).\n\nThis endpoint allows clients to submit a batch of employee data. The response of each request will be a `batch_id` which can be used to link the webhook event `EMPLOYEE_BATCH_PROCESSED`. After the batch has been processed by RAIN's system, the webhook processor will notify the client with the ingestion result. More details about the webhook event can be found in _Topic Employee Event_.\n\n# 2.4. Submitting Timekeeping Data\n\nTo submit employees' timekeeping data to RAIN's Data Ingestion API, the client will need to use the [Timekeeping Ingestion endpoint](#4492fca9-f137-4a1d-a5ee-d7cca9ff811f).\n\nThis endpoint allows clients to submit a batch of the employees' timekeeping data. The response of each request will be a `batch_id` which can be used to link the webhook event `TIMEKEEPING_BATCH_PROCESSED`. After the batch has been processed by RAIN's system, the webhook processor will notify the client with the ingestion result. More details about the webhook event can be found in _Topic Timekeeping Event_.\n\n# 2.5. Monitoring Webhooks Events\n\nConsidering the asynchronous processing, all the results of the processing operations will be communicated via webhook event.\n\n### Requirements\n\nTo be able to receive these events, the client must provide to RAIN an endpoint that accepts a `POST` request containing an `API KEY` in the header.\n\nThe request body content will have the event's details, wherein the client will be able to get the results of the asynchronous processing.\n\nThe following request is an example of what RAIN will be sending to the client's webhook endpoint.\n\n``` json\ncurl --location --request POST 'api-client-example.com/webhook' \\\n--header 'x-api-key: valid-api-key' \\\n--header 'Content-Type: application/json' \\\n--data-raw '{\n  \"type\": \"EMPLOYEE_BATCH_PROCESSED\",\n  \"body\": {\n    \"batch_id\": \"uuid\",\n    \"employer_code\": \"testeintimp\",\n    \"employees\": [\n      {\n        \"employee_code\": \"70155dbc-480d-492d-9d58-4eaff1f5a31a\",\n        \"status\": \"PROCESSED\"\n      }\n    ]\n  }\n}\n'\n\n ```\n\n### Event Fields\n\nThe table below summarizes the fields for the events:\n\n| **Field name** | **Description** |\n| --- | --- |\n| type | Type of event  <br>Enum:  <br>`EMPLOYEE_BATCH_PROCESSED`,  <br>`TIMEKEEPING_BATCH_PROCESSED`,  <br>`CERTIFICATE_RENEWAL` |\n| body.batch_id | Unique ID for a specific data ingestion execution |\n| body.employer_code | Unique ID from the employer that the employee belongs to. |\n| body.download_link | Download link for a certificate encrypted PGP file |\n| employees.employee_code | Employee's ID from client system |\n| employees.status | Employee's data ingestion result  <br>Enum:  <br>`PROCESSED`, `ERROR` |\n| timekeepings.timekeeping_code | Employee's timekeeping ID from client system |\n| timekeepings.status | Employee's timekeeping data ingestion result  <br>Enum:  <br>`PROCESSED`, `ERROR` |\n\n# 2.6. Event Types\n\n### Employee event\n\nThe `body.employees` field contains all the processed status of each employee for a specific batch\n\n#### Event example:\n\n``` json\n{\n  \"type\": \"EMPLOYEE_BATCH_PROCESSED\",\n  \"body\": {\n    \"batch_id\": \"uuid\",\n    \"employer_code\": \"string\",\n    \"employees\": [\n      {\n        \"employee_code\": \"70155dbc-480d-492d-9d58-4eaff1f5a31a\",\n        \"status\": \"PROCESSED\"\n      }\n    ]\n  }\n}\n\n ```\n\n### Timekeeping event\n\nThe `body.timekeepings` field contains the processed status of each timekeeping for a specific batch.\n\n#### Event example:\n\n``` json\n{\n  \"type\": \"TIMEKEEPING_BATCH_PROCESSED\",\n  \"body\": {\n    \"batch_id\": \"uuid\",\n    \"timekeepings\": [\n      {\n        \"timekeeping_code\": \"70155dbc-480d-492d-9d58-4eaff1f5a31a\",\n        \"status\": \"PROCESSED\"\n      }\n    ]\n  }\n}\n\n ```\n\n### Certificate Renewal Event\n\nThe `body.download_link_key` and `body.download_link_pem` are temporary downloadable encrypted PGP files that contain the mTLS certificate key and pem file, respectively. These files must be sent in all requests in order to access RAIN's services.\n\n``` json\n{\n  \"type\": \"CERTIFICATE_RENEWAL\",\n  \"body\": {\n    \"download_link_key\": \"https://url-download.com/client.key.gpg\",\n    \"download_link_pem\": \"https://url-download.com/client.pem.gpg\"\n  }\n}\n\n ```\n\n### Reading the encrypted PGP file\n\nEach download link is going to contain an encrypted PGP file. Decrypt each of them with the PGP private key generated previously to get the file content.\n\n# 2.7. API Rate Limit\n\nTo help manage the amount of requests to RAIN's systems, limits are set on the number of requests that can be sent to the API. These limits are established to provide a reliable and scalable system.\n\n| **Resource** | **Rate** |\n| --- | --- |\n| Authentication | 10 reqs/sec |\n| Employer | 10 reqs/sec |\n| Employee | 10 reqs/sec |\n| Timekeeping | 10 reqs/sec |\n\n# 3\\. Important\n\nIn order to use any of the API resources, it is **required** to send the TLS certificates along with the requests.\n\nCurl Example:\n\n```\ncurl --key client.key --cert client.pem --location \\\n--request POST 'https://api.data-ingestion.rain.us/{{path}}'\n\n ```\n\nTo setup Postman certificate settings, follow these [instructions](https://learning.postman.com/docs/sending-requests/certificates/).","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","isPublicCollection":true,"owner":"19628595","collectionId":"c5b65ac5-9492-46ec-a168-24e5263548d0","publishedId":"Uz5NiDCE","public":true,"publicUrl":"https://developers.rain.us","privateUrl":"https://go.postman.co/documentation/19628595-c5b65ac5-9492-46ec-a168-24e5263548d0","customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"3B4DCC"},"documentationLayout":"classic-double-column","customisation":null,"version":"8.10.1","publishDate":"2022-06-10T20:22:40.000Z","activeVersionTag":"latest","documentationTheme":"light","metaTags":{},"logos":{}},"statusCode":200},"environments":[{"name":"data-ingestion-api-env","id":"69eb23d9-e6af-47a5-9823-1afcfd3a8d91","owner":"19628595","values":[{"key":"client_id","value":"{Your client id provided by RAIN}","enabled":true,"type":"default"},{"key":"client_secret","value":"{Your client secret provided by RAIN}","enabled":true,"type":"default"},{"key":"scope","value":"{Your scope provided by Rain}","enabled":true,"type":"default"},{"key":"api_url","value":"{URL for the desired environment}","enabled":true,"type":"default"},{"key":"x-api-key","value":"{Your API Key provided by RAIN}","enabled":true,"type":"default"},{"key":"access_token","value":"{Generated by requesting POST /v1/oauth2/token}","enabled":true,"type":"any"}],"published":true}],"user":{"authenticated":false,"permissions":{"publish":false}},"run":{"button":{"js":"https://run.pstmn.io/button.js","css":"https://run.pstmn.io/button.css"}},"web":"https://www.getpostman.com/","team":{"logo":"https://res.cloudinary.com/postman/image/upload/t_team_logo_pubdoc/v1/team/768118b36f06c94b0306958b980558e6915839447e859fe16906e29d683976f0","favicon":"https://rain.us/favicon.ico"},"isEnvFetchError":false,"languages":"[{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"HttpClient\"},{\"key\":\"csharp\",\"label\":\"C#\",\"variant\":\"RestSharp\"},{\"key\":\"curl\",\"label\":\"cURL\",\"variant\":\"cURL\"},{\"key\":\"dart\",\"label\":\"Dart\",\"variant\":\"http\"},{\"key\":\"go\",\"label\":\"Go\",\"variant\":\"Native\"},{\"key\":\"http\",\"label\":\"HTTP\",\"variant\":\"HTTP\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"OkHttp\"},{\"key\":\"java\",\"label\":\"Java\",\"variant\":\"Unirest\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"Fetch\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"jQuery\"},{\"key\":\"javascript\",\"label\":\"JavaScript\",\"variant\":\"XHR\"},{\"key\":\"c\",\"label\":\"C\",\"variant\":\"libcurl\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Axios\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Native\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Request\"},{\"key\":\"nodejs\",\"label\":\"NodeJs\",\"variant\":\"Unirest\"},{\"key\":\"objective-c\",\"label\":\"Objective-C\",\"variant\":\"NSURLSession\"},{\"key\":\"ocaml\",\"label\":\"OCaml\",\"variant\":\"Cohttp\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"cURL\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"Guzzle\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"HTTP_Request2\"},{\"key\":\"php\",\"label\":\"PHP\",\"variant\":\"pecl_http\"},{\"key\":\"powershell\",\"label\":\"PowerShell\",\"variant\":\"RestMethod\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"http.client\"},{\"key\":\"python\",\"label\":\"Python\",\"variant\":\"Requests\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"httr\"},{\"key\":\"r\",\"label\":\"R\",\"variant\":\"RCurl\"},{\"key\":\"ruby\",\"label\":\"Ruby\",\"variant\":\"Net::HTTP\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"Httpie\"},{\"key\":\"shell\",\"label\":\"Shell\",\"variant\":\"wget\"},{\"key\":\"swift\",\"label\":\"Swift\",\"variant\":\"URLSession\"}]","languageSettings":[{"key":"csharp","label":"C#","variant":"HttpClient"},{"key":"csharp","label":"C#","variant":"RestSharp"},{"key":"curl","label":"cURL","variant":"cURL"},{"key":"dart","label":"Dart","variant":"http"},{"key":"go","label":"Go","variant":"Native"},{"key":"http","label":"HTTP","variant":"HTTP"},{"key":"java","label":"Java","variant":"OkHttp"},{"key":"java","label":"Java","variant":"Unirest"},{"key":"javascript","label":"JavaScript","variant":"Fetch"},{"key":"javascript","label":"JavaScript","variant":"jQuery"},{"key":"javascript","label":"JavaScript","variant":"XHR"},{"key":"c","label":"C","variant":"libcurl"},{"key":"nodejs","label":"NodeJs","variant":"Axios"},{"key":"nodejs","label":"NodeJs","variant":"Native"},{"key":"nodejs","label":"NodeJs","variant":"Request"},{"key":"nodejs","label":"NodeJs","variant":"Unirest"},{"key":"objective-c","label":"Objective-C","variant":"NSURLSession"},{"key":"ocaml","label":"OCaml","variant":"Cohttp"},{"key":"php","label":"PHP","variant":"cURL"},{"key":"php","label":"PHP","variant":"Guzzle"},{"key":"php","label":"PHP","variant":"HTTP_Request2"},{"key":"php","label":"PHP","variant":"pecl_http"},{"key":"powershell","label":"PowerShell","variant":"RestMethod"},{"key":"python","label":"Python","variant":"http.client"},{"key":"python","label":"Python","variant":"Requests"},{"key":"r","label":"R","variant":"httr"},{"key":"r","label":"R","variant":"RCurl"},{"key":"ruby","label":"Ruby","variant":"Net::HTTP"},{"key":"shell","label":"Shell","variant":"Httpie"},{"key":"shell","label":"Shell","variant":"wget"},{"key":"swift","label":"Swift","variant":"URLSession"}],"languageOptions":[{"label":"C# - HttpClient","value":"csharp - HttpClient - C#"},{"label":"C# - RestSharp","value":"csharp - RestSharp - C#"},{"label":"cURL - cURL","value":"curl - cURL - cURL"},{"label":"Dart - http","value":"dart - http - Dart"},{"label":"Go - Native","value":"go - Native - Go"},{"label":"HTTP - HTTP","value":"http - HTTP - HTTP"},{"label":"Java - OkHttp","value":"java - OkHttp - Java"},{"label":"Java - Unirest","value":"java - Unirest - Java"},{"label":"JavaScript - Fetch","value":"javascript - Fetch - JavaScript"},{"label":"JavaScript - jQuery","value":"javascript - jQuery - JavaScript"},{"label":"JavaScript - XHR","value":"javascript - XHR - JavaScript"},{"label":"C - libcurl","value":"c - libcurl - C"},{"label":"NodeJs - Axios","value":"nodejs - Axios - NodeJs"},{"label":"NodeJs - Native","value":"nodejs - Native - NodeJs"},{"label":"NodeJs - Request","value":"nodejs - Request - NodeJs"},{"label":"NodeJs - Unirest","value":"nodejs - Unirest - NodeJs"},{"label":"Objective-C - NSURLSession","value":"objective-c - NSURLSession - Objective-C"},{"label":"OCaml - Cohttp","value":"ocaml - Cohttp - OCaml"},{"label":"PHP - cURL","value":"php - cURL - PHP"},{"label":"PHP - Guzzle","value":"php - Guzzle - PHP"},{"label":"PHP - HTTP_Request2","value":"php - HTTP_Request2 - PHP"},{"label":"PHP - pecl_http","value":"php - pecl_http - PHP"},{"label":"PowerShell - RestMethod","value":"powershell - RestMethod - PowerShell"},{"label":"Python - http.client","value":"python - http.client - Python"},{"label":"Python - Requests","value":"python - Requests - Python"},{"label":"R - httr","value":"r - httr - R"},{"label":"R - RCurl","value":"r - RCurl - R"},{"label":"Ruby - Net::HTTP","value":"ruby - Net::HTTP - Ruby"},{"label":"Shell - Httpie","value":"shell - Httpie - Shell"},{"label":"Shell - wget","value":"shell - wget - Shell"},{"label":"Swift - URLSession","value":"swift - URLSession - Swift"}],"layoutOptions":[{"value":"classic-single-column","label":"Single Column"},{"value":"classic-double-column","label":"Double Column"}],"versionOptions":[],"environmentOptions":[{"value":"0","label":"No Environment"},{"label":"data-ingestion-api-env","value":"19628595-69eb23d9-e6af-47a5-9823-1afcfd3a8d91"}],"canonicalUrl":"https://developers.rain.us/view/metadata/Uz5NiDCE"}