{"id":19982491,"url":"https://github.com/netlify/addons","last_synced_at":"2026-02-04T22:36:22.422Z","repository":{"id":42216534,"uuid":"108343713","full_name":"netlify/addons","owner":"netlify","description":"Netlify add-on documentation","archived":false,"fork":false,"pushed_at":"2023-07-18T21:37:48.000Z","size":648,"stargazers_count":35,"open_issues_count":43,"forks_count":11,"subscribers_count":27,"default_branch":"master","last_synced_at":"2026-01-15T17:00:32.117Z","etag":null,"topics":["add-ons","marketplace","platform"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/netlify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-10-26T01:00:31.000Z","updated_at":"2025-12-16T01:36:22.000Z","dependencies_parsed_at":"2025-07-04T08:44:37.544Z","dependency_job_id":null,"html_url":"https://github.com/netlify/addons","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/netlify/addons","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Faddons","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Faddons/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Faddons/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Faddons/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/netlify","download_url":"https://codeload.github.com/netlify/addons/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Faddons/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29098239,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-04T21:05:08.033Z","status":"ssl_error","status_checked_at":"2026-02-04T21:04:53.031Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["add-ons","marketplace","platform"],"created_at":"2024-11-13T04:11:46.910Z","updated_at":"2026-02-04T22:36:22.402Z","avatar_url":"https://github.com/netlify.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Building Add-on integrations with Netlify\n\nA Netlify add-on is a way for Netlify users to extend their site functionality.\n\n**Some examples of add-ons:**\n\n- Automatically inject Sentry error tracking into your app\n- Provision a new Fauna database\n- Setup `env` variables in Netlify's build context for users Automatically\n- ...\n\n\u003e **Tip:** \n\u003e Before developing a Netlify add-on, consider creating a [Build Plugin](https://docs.netlify.com/configure-builds/build-plugins) for your use case instead. Build Plugins are a newer and more streamlined way to integrate with Netlify. They’re faster to develop, and users can install them directly from the Netlify UI.\n\n## Table of Contents\n\u003c!-- AUTO-GENERATED-CONTENT:START (TOC:collapse=true\u0026collapseText=Click to expand) --\u003e\n\u003cdetails\u003e\n\u003csummary\u003eClick to expand\u003c/summary\u003e\n\n- [Getting Started](#getting-started)\n- [Add-on Provisioning Flow](#add-on-provisioning-flow)\n- [Add-on API](#add-on-api)\n  * [`GET /manifest` - Manifest Endpoint](#get-manifest---manifest-endpoint)\n    + [Payload from Netlify](#payload-from-netlify)\n    + [Response to Netlify](#response-to-netlify)\n  * [`POST /instances` - Create Add-on Instance](#post-instances---create-add-on-instance)\n    + [Payload from Netlify](#payload-from-netlify-1)\n    + [Response to Netlify](#response-to-netlify-1)\n  * [`PUT /instances/:id` - Updating Add-on Instance](#put-instancesid---updating-add-on-instance)\n    + [Payload from Netlify](#payload-from-netlify-2)\n    + [Response to Netlify](#response-to-netlify-2)\n  * [`DELETE /instances/:id` - Deleting Add-on Instance](#delete-instancesid---deleting-add-on-instance)\n    + [Payload from Netlify](#payload-from-netlify-3)\n    + [Response to Netlify](#response-to-netlify-3)\n  * [`GET /instances/:id` - Getting Add-on Instance](#get-instancesid---getting-add-on-instance)\n    + [Payload from Netlify](#payload-from-netlify-4)\n    + [Response to Netlify](#response-to-netlify-4)\n- [Add-on Authenication](#add-on-authenication)\n- [Proxied URLs](#proxied-urls)\n  * [Request Headers](#request-headers)\n  * [Verification with JWS](#verification-with-jws)\n  * [User-Level Authentication with JWTs](#user-level-authentication-with-jwts)\n- [Registering your add-on](#registering-your-add-on)\n- [Example Implementations](#example-implementations)\n\n\u003c/details\u003e\n\u003c!-- AUTO-GENERATED-CONTENT:END --\u003e\n\n## Getting Started\n\nEach netlify add-on service must offer a [management API](#add-on-api) that Netlify will use to provision the third party service for new Netlify sites.\n\nThe management API also allows for Netlify to manage configuration settings and update the plans for your third party service.\n\n## Add-on Provisioning Flow\n\n\u003cimg width=\"100%\" alt=\"provisioning flow for repo\" src=\"https://user-images.githubusercontent.com/532272/45775428-93c74000-bc04-11e8-9a27-084170353563.png\"\u003e\n\n\n## Add-on API\n\nIn order for Netlify customers to create and manage their own instances of your service, you'll need to create a management API that exposes the following endpoints:\n\n```\nGET     /manifest       # returns the manifest \u0026 configuration details for your service\nPOST    /instances      # create a new instance of your service\nGET     /instances/:id  # get the current configuration of an instance\nPUT     /instances/:id  # update the configuration of an instance\nDELETE  /instances/:id  # delete an instance\n```\n\n### `GET /manifest` - Manifest Endpoint\n\nThe manifest endpoint of a Netlify add-on is used to return information about your service to the Netlify user.\n\n#### Payload from Netlify\n\nThe body of the payload from Netlify is empty.\n\n#### Response to Netlify\n\n**The manifest includes:**\n\n- `name` (required) - The name of your add-on\n- `description` (required) - A brief description of your add-on\n- `admin_url` (optional) - URL used for SSO when netlify users run `netlify addons:auth addonname`\n- `config` (optional) - The inputs required from the user for the add-on to provision itself.\n\n**Here is an example response to Netlify:**\n\n```js\n{\n  statusCode: 200,\n  body: JSON.stringify({\n    name: \"My Awesome Integration\",\n    description: \"This addon does XYZ.\",\n    admin_url: 'https://your-admin-url.com',\n    config: {\n      \"optionOne\": {\n        /* An alternate, human-friendly name. */\n        \"displayName\": \"Human friendly name\",\n        /*  Description of option shown to user  */\n        \"description\": \"This option does xyz. For more info see the docs http://docs.com/link\",\n        /*  Type of field\n        \"type\": \"string\",  */\n        /*  If is required or not\n        \"required\": true,  */\n      },\n      \"optionTwo\": {\n        \"displayName\": \"Second Human friendly name\",\n        \"type\": \"string\"\n      },\n      \"fooBarZaz\": {\n        \"displayName\": \"Third Human friendly name\",\n        \"description\": \"This option does xyz. For more info see the docs http://docs.com/link\",\n        \"type\": \"string\",\n      },\n    },\n  })\n}\n```\n\nManifest values are cached by Netlify for 24 hours.\n\n### `POST /instances` - Create Add-on Instance\n\nWhen a customer adds an instance of your add-on to a site, Netlify will `POST` to `your-management-api.com/instances/`\n\nA Netlify user can add an instance of your service by running:\n\n```bash\nnetlify addons:create your-addon-namespace --valueOne xyz --otherConfigValue abc\n```\n\nThat kicks off the following flow:\n\n#### Payload from Netlify\n\n**The `POST` request from Netlify to your service occurs**\n\nHere is an example request body **to your management endpoint**:\n\n```js\n{\n  // Unique ID generated by Netlify\n  uuid: '2e65dd70-523d-48d8-8826-a93229d7ec01',\n  account: '5902622bcf321c7359e97e52',\n  config: {\n    site_url: 'https://calling-site-from-netlify.netlify.com',\n    jwt: {\n      secret: 'xyz-netlify-secret'\n    },\n    // User defined configuration values\n    config: {\n      name: 'woooooo'\n    },\n    // Netlify Site id\n    site_id: '2e65dd70-523d-48d8-8826-a93229d7ec01',\n    // Your service ID slug\n    service_id: 'express-example',\n    service_instance: {\n      config: { name: 'woooooo' }\n    },\n    // If your add-on needs to trigger site rebuilds we will send a build hook\n    incoming_hook_url: 'https://api.netlify.com/build_hooks/123xyz'\n  }\n}\n```\n\n- `uuid`: Unique ID generated by Netlify.\n- `config`: Fields and values you need for configuring your service for a customer.\n\nYou will want to take this data, provision your application resources and return a response.\n\n#### Response to Netlify\n\n**Return a `201` response from your service back to Netlify**\n\n```js\n{\n  // `id` (required) - A unique ID generated by you, for reference within your own API\n  id: uuid(),\n  // `message` (optional) - Message back to user.\n  message: 'You have created the addon. Here is link to further instructions http://link.com',\n  // `endpoint` (optional) - Proxied endpoint.\n  // This will be callable at https://user-netlify-site.com/.netlify/your-addon-namespace\n  endpoint: \"https://my-endpoint.example.com\",\n  /* `config` (optional) - This can return back exactly what was received in the POST request, or include additional fields or altered values. This should also be what is returned in response to a GET request to /instances/:id */\n  config: {},\n  // `env` (optional) - Environment Keys accessible by Netlify user in build context \u0026 in functions\n  env: {\n    'YOUR_SERVICE_API_SECRET': 'value'\n  },\n  // `snippets` (optional) - JS Snippet content to inject into the calling Netlify site\n  snippets: [\n    {\n      title: 'Snippet From Demo App',\n      position: 'head',\n      html: `\u003cscript\u003econsole.log(\"Hello from ${logValue}\")\u003c/script\u003e`\n    }\n  ]\n}\n```\n\n- `id` A unique ID generated by you, for reference within your own API. Any string is valid for our purposes. This will be included in the headers and JWS for all API calls from Netlify. This `id` is also what is used in all subsequent `instances/${id}` update/get/delete calls to your remote API.\n- `env`: Set Environment variable for the Netlify user to access during site build or inside of their Netlify functions context.\n- `snippets`: Inject javascript snippets into the header or footer of the calling Netlify Site.\n\nThough not implemented yet, we plan to include a `state` field, which will allow your service to handle async provisioning, in case it takes some amount of time to activate the new service.\n\n**Mocking POST requests**\n\nFor local testing purposes you can mock the POST requests. [Read more here.](https://github.com/netlify/addons/issues/17)\n\n### `PUT /instances/:id` - Updating Add-on Instance\n\nYou can allow Netlify users to update your service instance.\n\nThis is achieved by the Netlify user running:\n\n```bash\n# Option 1. Run through configuration prompts from the /manifest endpoint\nnetlify addons:config your-addon-namespace\n\n# Option 2. Run command with values for no prompts\nnetlify addons:config your-addon-namespace --valueOne xyz --otherConfigValue abc\n```\n\n#### Payload from Netlify\n\n**The `PUT` request from Netlify to your service `/instances/${id}` occurs**\n\nThe ID of the service instance is included in the path parameters. This `id` was generated initially by your `POST` `/instances` implementation. (see \"Create an Instance\")\n\nThe body of the update request looks like this:\n\n```js\n{\n  config: {\n    name: 'noooooooo'\n  }\n}\n```\n\nRun your services update logic here and then return any updated values back to the Netlify site.\n\n#### Response to Netlify\n\n**Return a `200` response from your service back to Netlify**\n\nReturn any updated values from the users request\n\nHere is an example response with updated `env` values and an updated `snippet`\n\n```js\n{\n  env: {\n    'YOUR_SERVICE_API_SECRET': 'updated-env-value'\n  },\n  snippets: [\n    {\n      title: 'Snippet From Demo App',\n      position: 'head',\n      html: `\u003cscript\u003econsole.log(\"Updated snippet content\")\u003c/script\u003e`\n    }\n  ]\n}\n```\n\n### `DELETE /instances/:id` - Deleting Add-on Instance\n\nWhen a Netlify user removes your add-on, Netlify sends a `DELETE` request to your service to handle deprovisioning.\n\nUsers can remove add-ons like so:\n\n```bash\nnetlify addons:delete your-addon-namespace\n```\n\n#### Payload from Netlify\n\nWhen this happens, the following occurs:\n\n**Netlify sends a `DELETE` request from to your service `/instances/${id}`**\n\nThis request has no body but includes the `id` of the instance in the path `/instances/${id}`. This `id` was generated initially by your `POST` `/instances` implementation. (see \"Create an Instance\")\n\nRun your deletion logic and optionally return data back to Netlify.\n\n#### Response to Netlify\n\n**Return a `204` response from your service back to Netlify to verify the deletion was successful**\n\n```js\n{\n  statusCode: 204, // \u003c-- delete must respond back with 204.\n}\n```\n\n### `GET /instances/:id` - Getting Add-on Instance\n\nNetlify users get information about your service instance like so:\n\n```bash\nnetlify addons:list\n```\n\n#### Payload from Netlify\n\n**The `GET` request from Netlify to your service `/instances/${id}` occurs**.\n\nThis request has no body but includes the `id` of the instance.\n\nIn this request you would run the logic to fetch details about your instance based on the `id` from the path `/instances/${id}` and return them back to Netlify.\n\n#### Response to Netlify\n\n**Return a `200` response from your service back to Netlify**\n\n```js\n{\n  env: {\n    'YOUR_SERVICE_API_SECRET': 'value'\n  },\n  snippets: [\n    {\n      title: 'Snippet From Demo App',\n      position: 'head',\n      html: '\u003cscript\u003econsole.log(\"Hello from App\")\u003c/script\u003e'\n    }\n  ]\n}\n```\n\n## Add-on Authenication\n\nNetlify users can login to your service using the `admin_url` returned from your [`/manifest` endpoint](https://github.com/netlify/addons#get-manifest---manifest-endpoint).\n\nThe `admin_url` returned from `/manifest` will be be presented to the user in the Netlify UI \u0026 via the CLI `netlify addon:auth addonName`.\n\nThe admin url will have a JWT attached to it including these values:\n\n```json\n{\n  \"site_id\": \"49360df0-2dc2-406d-9b5f-fa3beb290eed\",\n  \"account_id\": \"5902622bcf321c7359e97e52\",\n  \"remote_id\": \"98cd0990-24dc-11e9-bb37-5d971cb376a0\"\n}\n```\n\nExample:\n\n```\nhttps://app.com/login#eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzaXRlX2lkIjoiNDkzNjBkZjAtMmRjMi00MDZkLTliNWYtZmEzYmViMjkwZWVkIiwiYWNjb3VudF9pZCI6IjU5MDI2MjJiY2YzMjFjNzM1OWU5N2U1MiIsInJlbW90ZV9pZCI6Ijk4Y2QwOTkwLTI0ZGMtMTFlOS1iYjM3LTVkOTcxY2IzNzZhMCJ9.GKMBcj6t9HML5CVtHQSL47z_gMyfSgOQj9EuvDlFpL8\n```\n\nThe `remote_id` corresponds to the `id` returned during the [creation flow](https://github.com/netlify/addons#response-to-netlify-1). You can use the `remote_id` in this URL to create a new user account for the resource or assign it to an existing user account in your service.\n\n## Proxied URLs\n\nWhen creating an add-on, if you return an `endpoint` with a URL to your service, a Netlify customer can send requests to\n\n```\nhttps://users-netlify-site.netlify.com/.netlify/\u003cyour-addon-namespace\u003e/*\n```\n\n**Example:**\n\nIf a user adds the `status-page` add-on and the creation of the `status-page` add-on returns an `endpoint` url of `http://third-party-service.com/xzy123/statue-page`, that endpoint will be available at:\n\n```\nhttps://users-netlify-site.netlify.com/.netlify/status-page/*\n```\n\nA call to `https://users-netlify-site.netlify.com/.netlify/status-page/` will be proxied through to the original service URL of `http://third-party-service.com/xzy123/statue-page`.\n\n### Request Headers\n\nAll requests will include the following headers:\n\n```\nX-NF-UUID: 1234-1234-1234\nX-NF-ID: 5a76f-b3902\nX-NF-SITE-URL: https://my-project.netlify.com\n```\n\n- `X-NF-UUID`: The unique UUID generated by Netlify and sent to your management API when provisioning the instance.\n- `X-NF-ID`: The unique ID returned from your management API when provisioning the instance.\n- `X-NF-SITE-URL`: The URL of the Netlify-hosted site associated with the instance.\n\n### Verification with JWS\n\nThough the headers above can be useful for quick troubleshooting and testing during development, they are vulnerable to impersonation attacks, and should not be used in production. Instead, use the JSON Web Signature (JWS) we'll include the header `X-NF-SIGN`. The JWS secret will match the bearer token generated when you first register your microservice on the platform, as described in [Getting started](getting-started.md). By verifying this secret, you'll know that the request is coming from Netlify. Also, because it's unique to your microservice, you can be sure that a leaked secret on another microservice will not impact the security of yours.\n\nThe JWS payload will be JSON with this format\n\n```json\n{\n  \"exp\": epoch-seconds,\n  \"site_url\": \"https://my-project.netlify.com\",\n  \"id\": \"5a76f-b3902\",\n  \"netlify_id\": \"1234-1234-1234\"\n}\n```\n\n- `exp`: Standard JWS expiration field.\n- `site_url`: The URL of the Netlify-hosted site associated with the instance, like `X-NF-SITE-URL` above.\n- `id`: The unique ID returned from your management API when provisioning the instance, like `X-NF-ID` above.\n- `netlify_id`: The unique UUID generated by Netlify and sent to your management API when provisioning the instance, like `X-NF-SITE-URL` above.\n\n\n### User-Level Authentication with JWTs\n\nWhile the JWS described above may be used to verify the origin of a request, you may also want to verify certain information about the actual site user who triggered that request. Netlify handles this with JSON Web Tokens (JWTs) as a stateless identity layer.\n\nNetlify provides a built-in Identity service (which is actually a microservice addon itself, based on our open source [GoTrue](https://www.gotrueapi.org) project). However, any authentication service that can issue JWTs will work with Netlify's microservice gateway. Site builders can include one of these JWTs as a bearer token in the Authorization header for a site route, and Netlify will verify its signature against the site's identity secret stored in Netlify's backend. If the route points to your microservice (using the path at the beginning of this doc), Netlify will re-sign the JWT with your unique secret before passing the request on to your microservice.\n\n## Registering your add-on\n\nOur current plan is to create a developer panel where new partners can register a new add-on in our UI. It will require an application title, slug, description, icon, and an endpoint for the app's management API.\n\nFor now, you can register your add-on namespace/endpoint by [filling out this form](https://cli.netlify.com/register-addon) and we will get you set up in Netlify's add-on marketplace.\n\nWhen we register your add-on, we’ll generate an add-on secret that is unique to your service. All requests from Netlify to your add-on’s management API will contain an `X-Nf-Sign` authorization header. You can verify request are coming from Netlify by verifying the `X-Nf-Sign` header against your add-on secret.\n\nYour management API should verify this secret before accepting any requests.\n\nExample:\n\n```js\nconst jwt = require('jsonwebtoken')\nconst Your_Addon_Secret = 'generated-when-addon-registered'\n\n// inside your request handler:\nconst netlifySignedToken = req.headers['X-Nf-Sign']\nconst fromNetlify = jwt.verify(netlifySignedToken, Your_Addon_Secret)\n\nif (fromNetlify) {\n  // do stuff\n}\n```\n\nAfter your namespace is setup in Netlify, you will be able to run CLI command to test out your provisioning logic\n\n```bash\nnetlify addons:create your-name-space\n```\n\nIt’s common for add-on partners to create a `-staging` version of their add-on to test new features, like `your-addon-namespace-staging`. This gives a safe place for us to test and update changes to an addon before shipping updates to the master `your-addon-namespace` that is live for all Netlify users.\n\n## Example Implementations\n\nWe have created a couple example implementations of how an add-on REST API should work.\n\n- [An express app running on Heroku](./examples/express) |  [code](https://github.com/netlify/netlify-addons/blob/master/examples/express/index.js)\n- [A REST API running on AWS Lambda + APIGateway](./examples/serverless) |  [code](https://github.com/netlify/netlify-addons/blob/master/examples/serverless/handler.js)\n- [Using Netlify Functions](./examples/netlify-functions) |  [code](https://github.com/netlify/addons/blob/master/examples/netlify-functions/functions/addons.js#L28-L32)\n\nPlease let us know if you have any questions on how these work! Open an issue in this repo or ping us directly on slack.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetlify%2Faddons","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetlify%2Faddons","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetlify%2Faddons/lists"}