Developer API

Publish your site with your own code.

Use the Neocities API to manage your site from your own scripts and tools.

Quick start

Upload a file in one request

cURL is a command-line tool we will use to demonstrate API usage. Replace the placeholders below, and run this command from the directory that contains your file.

Use an API key instead of your password.

Open Settings, choose your site, and find API key. Keep the key private: it grants access to your site files.

Upload a file
curl -H "Authorization: Bearer YOUR_API_KEY" \
  -F "hello.html=@local.html" \
  https://neocities.org/api/upload

local.html is the file on your computer. Neocities saves it to your site as hello.html.

Credentials

Authentication, requests, and responses

Most endpoints require bearer authentication with an API key.

Request format

GET requests
Send parameters in the URL query string.
POST requests
Send application/x-www-form-urlencoded form fields, except /api/upload, which uses multipart/form-data.
Site paths
Use site-relative paths and forward slashes.
Responses are JSON, except file downloads.

Successful requests return HTTP 200 with "result": "success" plus an endpoint-specific message, files, or info field. Request errors use 400, invalid credentials use 403, and unknown endpoints use 404. Error bodies include error_type and message.

Example error response (HTTP 400)
{
  "result": "error",
  "error_type": "missing_path",
  "message": "you must provide path"
}

Be a good neighbor

Usage guidelines

Please use restraint when developing. Excessive calls to the API can lead to a temporary block.

  • Keep recurring updates to once per ten minutes.Avoid bursts of unnecessary requests. Do not do a lot of separate requests in parallel.
  • Only publish what changed.Use the hash endpoint when your deploy tool needs to compare local and remote files first.
  • Do not manipulate rankings or activity signals.Sites that manufacture updates to game discovery may be removed from the browse page.
  • Respect other people’s sites.Do not scrape, mirror, or data-mine the Neocities community through the API.

API reference

POST

/api/upload

Upload one or more files with a multipart/form-data request. Each field name becomes the destination path on your site.

Form fields

destination pathrequired
The uploaded file. Add another field for every file you want to publish.
Upload two files
curl -H "Authorization: Bearer YOUR_API_KEY" \
  -F "index.html=@localindex.html" \
  -F "css/style.css=@css/localstyle.css" \
  https://neocities.org/api/upload
Example response
{
  "result": "success",
  "message": "your file(s) have been successfully uploaded"
}

Missing destination directories are created automatically. Every file is validated before storage begins, and the site's file-type, storage, and file-count limits apply. Each file and the combined request are limited to 100 MB and must fit the site's remaining storage. Uploading an identical file succeeds and reports that it is already up to date.

POST

/api/create_directory

Create a directory on your site. Missing parent directories are created along the way.

Form fields

pathrequired
The directory path to create, such as images/cats.
Create a nested directory
curl -H "Authorization: Bearer YOUR_API_KEY" \
  -d "path=images/cats" \
  https://neocities.org/api/create_directory
Example response
{
  "result": "success",
  "message": "directory has been created"
}

The request fails if a file or directory already exists at the destination.

POST

/api/rename

Move or rename an existing file or directory.

Form fields

pathrequired
The current path.
new_pathrequired
The new path.
Rename a file
curl -H "Authorization: Bearer YOUR_API_KEY" \
  -d "path=drafts/about.html" \
  -d "new_path=about.html" \
  https://neocities.org/api/rename
Example response
{
  "result": "success",
  "message": "drafts/about.html has been renamed to about.html"
}

The destination’s parent directory must already exist, and an existing path cannot be overwritten. The root index.html cannot be moved. Moving a directory moves everything inside it, but a directory cannot be moved inside itself or renamed with an .htm or .html suffix. A file cannot be renamed to a type that the site is not allowed to upload.

POST

/api/delete

Delete one or more files or directories from your site. Deleting a directory also removes everything inside it.

Deletion cannot be undone.

The root directory and root index.html are protected. Every submitted path is checked before deletion starts, so a missing or invalid path cancels the entire request.

Form fields

filenames[]required
Repeat this field for each path you want to delete.
Delete two files
curl -H "Authorization: Bearer YOUR_API_KEY" \
  -d "filenames[]=old-banner.jpg" \
  -d "filenames[]=draft.html" \
  https://neocities.org/api/delete
Example response
{
  "result": "success",
  "message": "file(s) have been deleted"
}
GET

/api/list

List the files and directories on your site. With no path, the response includes the entire site recursively. With a path, it includes that directory’s immediate children.

Query parameters

pathoptional
Limit the response to the immediate children of a directory. Omit it, leave it blank, or use / to list the entire site.
List the images directory
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://neocities.org/api/list?path=images"
Example response
{
  "result": "success",
  "files": [
    {
      "path": "images/cats",
      "is_directory": true,
      "created_at": "Tue, 01 Sep 2026 12:00:00 +0000",
      "updated_at": "Tue, 01 Sep 2026 12:00:00 +0000"
    },
    {
      "path": "images/banner.jpg",
      "is_directory": false,
      "size": 1024,
      "created_at": "Tue, 01 Sep 2026 12:00:00 +0000",
      "updated_at": "Wed, 02 Sep 2026 15:30:00 +0000",
      "sha1_hash": "a9993e364706816aba3e25717850c26c9cd0d89d"
    }
  ]
}

Every record contains path, is_directory, created_at, and updated_at. Dates use RFC 2822 format. File records also contain size in bytes and sha1_hash; directory records do not. A missing directory returns an empty files array.

GET

/api/download

Download a single file. This endpoint returns the raw file body rather than a JSON response.

Query parameters

pathrequired
The path of the file to download. Directories cannot be downloaded.
Save a file locally
curl -H "Authorization: Bearer YOUR_API_KEY" \
  -o index.html \
  "https://neocities.org/api/download?path=index.html"

A successful response includes a content type inferred from the filename, plus Content-Length, Last-Modified, and SHA-1 ETag headers. Downloads use Cache-Control: private, no-store.

GET

/api/info

Read information about a Neocities site, including views, hits, dates, domain, supporter status, and tags.

Query parameters

sitenameoptional
Return public information for this site without authentication. With no parameter, credentials identify the site.
Get public site information
curl "https://neocities.org/api/info?sitename=youpi"
Example response
{
  "result": "success",
  "info": {
    "sitename": "youpi",
    "views": 1234,
    "hits": 5678,
    "created_at": "Tue, 01 Sep 2026 12:00:00 +0000",
    "last_updated": "Wed, 02 Sep 2026 15:30:00 +0000",
    "domain": null,
    "supporter": false,
    "tags": ["cats", "art"]
  }
}

The response’s info object contains sitename, views, hits, created_at, last_updated, domain, supporter, and tags. Dates use RFC 2822 format; last_updated and domain may be null.

POST

/api/upload_hash

Compare local SHA-1 hashes with the copies on your site. This is useful for skipping files that are already up to date before a deployment.

Form fields

file pathrepeatable
Use each site path as a field name and its SHA-1 hash as the value. Each path must map directly to a string; nested fields are rejected.
Check file hashes
curl -H "Authorization: Bearer YOUR_API_KEY" \
  --data-urlencode "index.html=YOUR_SHA1_HASH" \
  --data-urlencode "css/site.css=YOUR_CSS_SHA1_HASH" \
  https://neocities.org/api/upload_hash
Example response
{
  "result": "success",
  "files": {
    "index.html": true,
    "css/site.css": false
  }
}

The response maps each submitted path to true when the remote file has the same hash, or false when it needs to be uploaded.