Overview
Sites host browser-based tools inside Rippling, such as dashboards, calculators, and interactive guides. You can build a site with Rippling AI or upload HTML, CSS, and JavaScript that you built with another tool. Each site runs at app.rippling.com/sites/<api_name>, and only the people you give access can see it.
Use the Sites API to create and update sites from code, a function, or an AI agent. A site can also call the Rippling Platform APIs to read and write Rippling data.
Use a site when you need a flexible, polished experience, like a guide, calculator, or executive readout. Use a custom app when you need structured records, forms, approvals, and role-based permissions.
Key terms:
- Site: A web app hosted in Rippling. A site is a single
.htmlfile or a set of files with an entry page, usuallyindex.html. - API name: The unique identifier for a site, used in its URL and in API requests. You set it when you create a site with the API. In Site Manager, Rippling generates it from the display name.
- Display name: The name people see in the Rippling sidebar and search results. The API returns it as
name. - Bundle: The set of files that's live on a site. Each site has one active bundle, identified by
current_bundle_id. Each time you replace or change the files, Rippling creates a new bundle. - Staged upload: Files you've uploaded but haven't attached to a site yet. Each staged upload has a
file_idand expires 1 hour after you presign it. - Entry path: The page that loads first when someone opens the site. Defaults to
index.html. - Admins and Viewers: The groups that can edit and view the site.
Available endpoints
| Endpoint | Description |
|---|---|
| GET List sites | Returns the sites you can view or edit. |
| GET Retrieve a specific site | Returns one site by its API name. |
| POST Create a presigned staged upload batch | Returns upload URLs for your site files. |
| POST Create a new site | Creates a site from a staged upload. |
| PATCH Update a site | Updates a site's details or replaces all of its files. |
| GET List files in the active bundle | Returns the files and folders in a site. |
| POST Apply file operations to a site bundle | Adds, renames, moves, or deletes individual files and folders. |
| DELETE Delete a site | Deletes a site. |
Suggested workflow
- Call POST Create a presigned staged upload batch to get an upload URL.
- Upload your
.htmlor.zipfile to that URL. - Call POST Create a new site with the
file_idfrom step 1. - To change the site later, call PATCH Update a site or POST Apply file operations to a site bundle.
- Call DELETE Delete a site when you no longer need it.
Requirements
- Rippling AI. Companies with Rippling AI automatically get access to the Rippling APIs, including the Sites API.
- An API token with the following scopes:
sites.readto fetch sites and their filessites.read-writeto create, update, and delete sites and their files
Fetch
List sites
Use GET List sites to return the sites you have view or edit access to. Results are paginated.
Request:
curl -L -X GET 'https://rest.ripplingapis.com/sites/?limit=50' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer REDACTED'
Response:
{
"__meta": {
"redacted_fields": []
},
"results": [
{
"id": "6748f1a2b3c4d5e6f7a8b9c0",
"name": "Employee Handbook",
"description": "Searchable company handbook",
"api_name": "employee_handbook",
"logo": null,
"current_bundle_id": "6748f1a2b3c4d5e6f7a8b9d1",
"admin_group_id": "6748f1a2b3c4d5e6f7a8b9e2",
"viewer_group_id": "6748f1a2b3c4d5e6f7a8b9f3",
"created_by": "6748f1a2b3c4d5e6f7a8ba04",
"created_at": "2026-10-22T14:30:00Z"
}
],
"next_link": null
}
| Response field | Description |
|---|---|
__meta.redacted_fields | Fields removed from the response because you don't have permission to see them. |
results[].id | The site's ID. |
results[].name | The site's display name. |
results[].description | The site's description, if it has one. |
results[].api_name | The site's unique API name, used in its URL. |
results[].logo | The URL of the site's logo, hosted by Rippling. |
results[].current_bundle_id | The ID of the site's active bundle. |
results[].admin_group_id | The ID of the group that can edit the site. |
results[].viewer_group_id | The ID of the group that can view the site. |
results[].created_by | The ID of the role that created the site. |
results[].created_at | The date and time the site was created. |
next_link | A link to the next page of results. null on the last page. |
Retrieve a site
Use GET Retrieve a specific site to return one site by its API name. The name filter on List sites matches any part of the display name, so use this endpoint when you need one exact site.
Request:
curl -L -X GET 'https://rest.ripplingapis.com/sites/employee_handbook/' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer REDACTED'
Response:
{
"id": "6748f1a2b3c4d5e6f7a8b9c0",
"name": "Employee Handbook",
"description": "Searchable company handbook",
"api_name": "employee_handbook",
"logo": null,
"current_bundle_id": "6748f1a2b3c4d5e6f7a8b9d1",
"admin_group_id": "6748f1a2b3c4d5e6f7a8b9e2",
"viewer_group_id": "6748f1a2b3c4d5e6f7a8b9f3",
"created_by": "6748f1a2b3c4d5e6f7a8ba04",
"created_at": "2026-10-22T14:30:00Z"
}
The fields are the same as a result in List sites.
List a site's files
Use GET List files in the active bundle to return the files and folders in a site's active bundle.
Request:
curl -L -X GET 'https://rest.ripplingapis.com/sites/employee_handbook/files/?recursive=true' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer REDACTED'
Response:
{
"bundle_id": "6748f1a2b3c4d5e6f7a8b9d1",
"entry_path": "index.html",
"parent_path": "",
"recursive": true,
"files": [
{
"path": "index.html",
"name": "index.html",
"parent_path": "",
"content_type": "text/html",
"size_bytes": 13517,
"sha256": "9f2c4e1b7a..."
},
{
"path": "assets/app.css",
"name": "app.css",
"parent_path": "assets",
"content_type": "text/css",
"size_bytes": 9420,
"sha256": "4b7d0a93e2..."
}
],
"directories": [
{
"path": "assets",
"name": "assets",
"parent_path": ""
}
]
}
| Response field | Description |
|---|---|
bundle_id | The ID of the active bundle. Use it as base_bundle_id when you change files. |
entry_path | The page that loads first. |
parent_path | The folder that was listed. |
recursive | Whether subfolders were included. |
files[].path | The file's full path in the site. |
files[].name | The file's name. |
files[].parent_path | The folder the file is in. |
files[].content_type | The file's media type, like text/html. |
files[].size_bytes | The file's size in bytes. |
files[].sha256 | A SHA-256 hash of the file's contents. Use it to check whether a file changed. |
directories[].path | The folder's full path. |
directories[].name | The folder's name. |
directories[].parent_path | The folder it's inside. |
Create
Creating a site takes three steps: get an upload URL, upload your file to it, and then create the site.
A site can include HTML, CSS, and JavaScript files, plus other assets like images and PDFs. A site can be up to 25 MB and include up to 200 files. If you upload a .zip without an index.html file, set entry_path to the page that should load first. In Site Manager, the upload fails with "Entry path index.html was not found."
Get an upload URL
Use POST Create a presigned staged upload batch to get a URL for each file you plan to upload. You use this same step to create a site, replace a site's files, or add a file.
Request:
curl -L -X POST 'https://rest.ripplingapis.com/sites/upload-batches/presign/' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer REDACTED'
Request body:
{
"file_intents": [
{
"client_ref": "handbook-upload-1",
"file_name": "site.zip"
}
]
}
| Request body field | Required | Description |
|---|---|---|
file_intents | Yes | The files you plan to upload. |
file_intents[].client_ref | Yes | Any unique ID you choose, so you can match each file to its upload URL. |
file_intents[].file_name | Yes | The file's name, like site.zip or index.html. |
Response:
{
"upload_batch_id": "6748f1a2b3c4d5e6f7a8bb00",
"files": [
{
"client_ref": "handbook-upload-1",
"file_id": "6748f1a2b3c4d5e6f7a8bb15",
"file_name": "site.zip",
"upload_url": "https://example-bucket.s3.amazonaws.com/",
"upload_fields": {
"key": "staged/6748f1a2b3c4d5e6f7a8bb15/site.zip",
"policy": "REDACTED",
"x-amz-signature": "REDACTED"
}
}
]
}
| Response field | Description |
|---|---|
upload_batch_id | The ID of the staged upload batch. You don't use it in later calls. |
files[].client_ref | The client_ref you sent, so you can match each file. |
files[].file_id | The staged upload ID. Use it to create or update the site. |
files[].file_name | The file name you sent. |
files[].status | The upload's status. |
files[].upload_url | The URL to upload the file to. |
files[].upload_fields | The form fields to send with the upload. The fields can vary, so send all of them exactly as returned. |
Pass files[].file_id to the create, update, and file operations endpoints. Passing upload_batch_id doesn't work.
Upload the file
Send a multipart POST to upload_url. Include every field from upload_fields, and then add the file as the last part. This request goes straight to storage, so don't include your Rippling token.
curl -L -X POST 'https://example-bucket.s3.amazonaws.com/' \
-F 'key=staged/6748f1a2b3c4d5e6f7a8bb15/site.zip' \
-F 'policy=REDACTED' \
-F 'x-amz-signature=REDACTED' \
-F 'file=@site.zip'
Create the site
Use POST Create a new site to create the site from your staged upload.
Request:
curl -L -X POST 'https://rest.ripplingapis.com/sites/' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer REDACTED'
Request body:
{
"name": "Employee Handbook",
"description": "Searchable company handbook",
"api_name": "employee_handbook",
"file_id": "6748f1a2b3c4d5e6f7a8bb15"
}
| Request body field | Required | Description |
|---|---|---|
name | Yes | The site's display name. |
api_name | Yes | The site's unique API name, used in its URL. |
file_id | Yes | The staged upload ID from the presign response. |
description | No | A description of the site. |
logo | No | A Rippling-hosted logo URL. |
entry_path | No | The page that loads first, like home.html. Required if your .zip doesn't include index.html. |
Response:
{
"id": "6748f1a2b3c4d5e6f7a8b9c0",
"name": "Employee Handbook",
"description": "Searchable company handbook",
"api_name": "employee_handbook",
"logo": null,
"current_bundle_id": "6748f1a2b3c4d5e6f7a8b9d1",
"admin_group_id": "6748f1a2b3c4d5e6f7a8b9e2",
"viewer_group_id": "6748f1a2b3c4d5e6f7a8b9f3",
"created_by": "6748f1a2b3c4d5e6f7a8ba04",
"created_at": "2026-10-27T10:30:00Z"
}
The fields are the same as a result in List sites.
You can use the same file_id for up to 1 hour after you presign it. Each time you use it, Rippling copies the files into a new bundle. After an hour, the staged upload is deleted.
Update
Update a site's details
Use PATCH Update a site to change a site's name, description, or logo. You don't need to upload anything for these changes.
Request:
curl -L -X PATCH 'https://rest.ripplingapis.com/sites/employee_handbook/' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer REDACTED'
Request body:
{
"name": "Employee Handbook 2027",
"description": "Updated for the new year"
}
| Request body field | Required | Description |
|---|---|---|
name | No | The site's new display name. |
description | No | The site's new description. |
logo | No | A new Rippling-hosted logo URL. |
file_id | No | A staged upload ID. Replaces all of the site's files. |
entry_path | No | The page that loads first. Required with file_id if the new .zip doesn't include index.html. |
Response:
{
"id": "6748f1a2b3c4d5e6f7a8b9c0",
"name": "Employee Handbook 2027",
"description": "Updated for the new year",
"api_name": "employee_handbook",
"logo": null,
"current_bundle_id": "6748f1a2b3c4d5e6f7a8b9d1",
"admin_group_id": "6748f1a2b3c4d5e6f7a8b9e2",
"viewer_group_id": "6748f1a2b3c4d5e6f7a8b9f3",
"created_by": "6748f1a2b3c4d5e6f7a8ba04",
"created_at": "2026-10-22T14:30:00Z"
}
The fields are the same as a result in List sites.
Replace all of a site's files
To replace the whole site, get an upload URL, upload the file, and then call PATCH Update a site with the new file_id:
{
"file_id": "6748f1a2b3c4d5e6f7a8bb27"
}
Everyone with access sees the new version right away.
Change individual files
Use POST Apply file operations to a site bundle to add, rename, move, or delete specific files and folders. All operations in one request succeed or fail together.
To add or replace a file, get an upload URL and upload the file first, then use its file_id in a put operation.
Request:
curl -L -X POST 'https://rest.ripplingapis.com/sites/employee_handbook/file-operations/' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer REDACTED'
Request body:
{
"base_bundle_id": "6748f1a2b3c4d5e6f7a8b9d1",
"operations": [
{
"op": "put",
"kind": "file",
"path": "assets/logo.png",
"file_id": "6748f1a2b3c4d5e6f7a8bb31"
},
{
"op": "rename",
"kind": "file",
"from_path": "about.html",
"to_path": "team.html"
},
{
"op": "delete",
"kind": "directory",
"path": "old-assets",
"recursive": true
}
]
}
| Request body field | Required | Description |
|---|---|---|
base_bundle_id | Yes | The site's current_bundle_id. |
operations | Yes | The changes to make. Must include at least one. |
operations[].op | Yes | put, rename, move, or delete. Folders support put, rename, and delete, but not move. |
operations[].kind | Yes | file or directory. |
operations[].path | For put and delete | The path of the file or folder. |
operations[].file_id | For put on a file | The staged upload ID for the file. |
operations[].from_path | For rename and move | The current path. |
operations[].to_path | For rename and move | The new path. |
operations[].recursive | No | For deleting a folder. Set to true to delete everything inside it. |
entry_path | No | A new entry page. If you leave it out, the current one stays. |
Response:
{
"id": "6748f1a2b3c4d5e6f7a8b9c0",
"name": "Employee Handbook",
"description": "Searchable company handbook",
"api_name": "employee_handbook",
"logo": null,
"current_bundle_id": "6748f1a2b3c4d5e6f7a8b9e7",
"admin_group_id": "6748f1a2b3c4d5e6f7a8b9e2",
"viewer_group_id": "6748f1a2b3c4d5e6f7a8b9f3",
"created_by": "6748f1a2b3c4d5e6f7a8ba04",
"created_at": "2026-10-22T14:30:00Z"
}
The response is the updated site, including its new current_bundle_id.
If base_bundle_id doesn't match the site's current bundle, the request returns 409. This happens when someone else changed the site after you fetched it. Get the latest current_bundle_id and try again.
Delete
Use DELETE Delete a site to delete a site.
Request:
curl -L -X DELETE 'https://rest.ripplingapis.com/sites/employee_handbook/' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer REDACTED'
A successful delete returns 204 No Content with no response body.
Use cases
Call Rippling APIs from a site
A site can read and write Rippling data through the Platform APIs. Each viewer only sees the data their own Rippling permissions allow. For example, a manager viewing a compensation benchmarking site only sees compensation for their direct reports. Data saved in the site's files, like hard-coded values or a bundled CSV, isn't filtered. Every viewer can see it.
A site can only use fields that the Rippling REST APIs expose. Before you build a site around a field, check that the field is available in the relevant API and that it returns the right data for each viewer. There are no cross-origin resource sharing (CORS) limits on calls from a site to rest.ripplingapis.com.
A site that calls POST, PATCH, or DELETE endpoints changes live data in Rippling. Before the call goes through, the viewer sees a consent notice and must click I understand. The notice tells them the site can change live data and can only use permissions they already have. If they click Go back, the notice closes and the request isn't sent. Viewers see the notice once for each version of the site. If you update a site and it still makes write calls, viewers see the notice again.
To build a site that writes data, you need the Sites creator with write API access permission. Everyone has it by default, and admins can remove it in the Permissions app. A site can only write if the person who created it or last updated it has this permission.
A site can't do anything the viewer couldn't do in Rippling themselves. If a viewer doesn't have permission to update a record, the site can't update it for them.
You don't create or store a token for this. When someone views your site, Rippling handles authentication for every fetch or XMLHttpRequest call the site makes to rest.ripplingapis.com. It creates a token for the viewer, sends the request, and returns the response to your site.
- Call the endpoints your site needs with a standard
fetchcall tohttps://rest.ripplingapis.com. Don't add anAuthorizationheader. - Handle errors for calls the viewer doesn't have permission to make.
- (Optional) To show information about the viewer, such as their work email, call GET Retrieve my SSO information.
Customize the following code for your setup:
async function listWorkers() {
const response = await fetch('https://rest.ripplingapis.com/workers/?limit=50', {
headers: { Accept: 'application/json' },
});
if (!response.ok) {
throw new Error(`Couldn't load workers: ${response.status}`);
}
const data = await response.json();
return data.results;
}
listWorkers().then((workers) => {
const list = document.querySelector('#workers');
for (const worker of workers) {
const item = document.createElement('li');
item.textContent = worker.work_email;
list.append(item);
}
});
Rippling only handles authentication when the site is viewed at app.rippling.com/sites/<api_name>. If you open the site's files directly on your computer, its API calls fail. Use sample data while you build, then test API calls after you upload the site.
Never put an API token in a site's HTML or JavaScript. Anyone who can view the site can read its code. Rippling replaces any token you add with the viewer's, so it doesn't change what the site can do.
Deploy a site from a function or agent
- Build the site files with your coding agent or a function.
- The first time, get an upload URL, upload the files, and create the site.
- After that, replace all of the site's files or change individual files.
Limits
Sites run in a sandboxed frame inside Rippling, which limits what they can do:
- Open external pages inside the site. Links to other websites need to open in a new tab, for example with
target="_blank". - Load content from other websites. A site can't call APIs or load images from other domains, such as map tiles.
- Read the query string. A site can't read the query parameters in the Rippling URL.
- Store data in the browser.
localStorage,sessionStorage, and cookies aren't available. Code that uses them throws an error. - Use any image, font, or audio source. Images can use
blob:anddata:URLs. Fonts can usedata:URLs only. Audio fromblob:anddata:URLs doesn't play. - Manage sites. A site can't call the Sites API. Those requests return
403. - Launch from an app tile. Sites appear in the Sites section of the sidebar.
- Ship in a package. You can't include a site in a distributable package.
The Sites API has no endpoint-specific rate limits. It follows the standard API limits: 600 requests per 10 seconds per token for each endpoint path. If you go over, the API returns 429 Too Many Requests. Retry with exponential backoff or the Retry-After header.
See also
- Control who can create and manage sites in the Help Center
- API tokens
- Functions guide