Customer.io Snippets API

Manage reusable content snippets for use in messages.

Operations 4

GET /v1/snippets List snippets #
POST /v1/snippets Create a snippet #
PUT /v1/snippets Update snippets #
DELETE /v1/snippets/{snippet_name} Delete a snippet #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/customer-io-snippets-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

customer-io-snippets-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  version: 1.0.0
  title: Customer.io App Snippets API
  description: Our App API provides ways to trigger messages and retrieve information about people, campaigns, broadcasts, and more.
servers:
- url: https://api.customer.io
  description: The base URL for broadcasts, transactional messages, and data-retrieval APIs. These endpoints use bearer authorization, and require a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app).
- url: https://api-eu.customer.io
  description: The base URL for broadcasts, transactional messages, and data-retrieval APIs (EU region). These endpoints use bearer authorization, and require a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app).
tags:
- name: Snippets
  description: Snippets are reusable pieces of messages, like a common email footer or link that you use in your messages. Use these endpoints to create, get, or delete snippets.
paths:
  /v1/snippets:
    servers:
    - url: https://api.customer.io
      description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app).
    get:
      summary: List snippets
      operationId: listSnippets
      security:
      - Bearer-Auth: []
      description: Returns a list of snippets in your workspace. Snippets are pieces of reusable content, like a common footer for your emails.
      tags:
      - Snippets
      responses:
        '200':
          description: Returns an array of `snippets`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  snippets:
                    type: array
                    items:
                      x-scalar-ignore: true
                      type: object
                      description: describes a piece of reusable content. You must provide a name for the snippet and the `value`—the content that appears in messages that use the snippet.
                      required:
                      - name
                      - value
                      properties:
                        name:
                          type: string
                          description: The name of the snippet, must be unique.
                        value:
                          type: string
                          description: The contents of the snippet.
                        updated_at:
                          type: integer
                          format: unix timestamp
                          description: The last date-time the snippet was updated.
                          readOnly: true
                      example:
                        name: address
                        value: <strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111
                        updated_at: 1582500000
      x-codeSamples:
      - lang: Shell + Curl
        source: "curl --request GET \\\n  --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  --url https://api.customer.io/v1/snippets"
      - lang: Node + Native
        source: "const http = require(\"https\");\n\nconst options = {\n  \"method\": \"GET\",\n  \"hostname\": \"api.customer.io\",\n  \"port\": null,\n  \"path\": \"/v1/snippets\",\n  \"headers\": {}\n};\n\nconst req = http.request(options, function (res) {\n  const chunks = [];\n\n  res.on(\"data\", function (chunk) {\n    chunks.push(chunk);\n  });\n\n  res.on(\"end\", function () {\n    const body = Buffer.concat(chunks);\n    console.log(body.toString());\n  });\n});\n\nreq.end();"
      - lang: Ruby + Native
        source: 'require ''uri''

          require ''net/http''

          require ''openssl''


          url = URI("https://api.customer.io/v1/snippets")


          http = Net::HTTP.new(url.host, url.port)

          http.use_ssl = true

          http.verify_mode = OpenSSL::SSL::VERIFY_NONE


          request = Net::HTTP::Get.new(url)


          response = http.request(request)

          puts response.read_body'
      - lang: Python + Python3
        source: 'import http.client


          conn = http.client.HTTPSConnection("api.customer.io")


          conn.request("GET", "/v1/snippets")


          res = conn.getresponse()

          data = res.read()


          print(data.decode("utf-8"))'
      - lang: Go + Native
        source: "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/snippets\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}"
    post:
      summary: Create a snippet
      operationId: createSnippet
      security:
      - Bearer-Auth: []
      description: Create a new snippet. If a snippet with that name already exists, we'll return a `422` error. If the value contains Liquid, we validate it.
      tags:
      - Snippets
      requestBody:
        content:
          application/json:
            schema:
              x-scalar-ignore: true
              type: object
              description: Request body for creating or updating a snippet. Only `name` and `value` are accepted; `updated_at` is returned in responses only.
              required:
              - name
              - value
              properties:
                name:
                  type: string
                  maxLength: 150
                  description: The name of the snippet, must be unique. Trimmed of leading and trailing whitespace before storage.
                value:
                  type: string
                  description: The contents of the snippet (plain text or Liquid). Trimmed of leading and trailing whitespace before storage. Max length is environment-specific (default 16000).
              example:
                name: address
                value: <strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111
      responses:
        '200':
          description: Returns the created snippet.
          content:
            application/json:
              schema:
                type: object
                properties:
                  snippet:
                    x-scalar-ignore: true
                    type: object
                    description: describes a piece of reusable content. You must provide a name for the snippet and the `value`—the content that appears in messages that use the snippet.
                    required:
                    - name
                    - value
                    properties:
                      name:
                        type: string
                        description: The name of the snippet, must be unique.
                      value:
                        type: string
                        description: The contents of the snippet.
                      updated_at:
                        type: integer
                        format: unix timestamp
                        description: The last date-time the snippet was updated.
                        readOnly: true
                    example:
                      name: address
                      value: <strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111
                      updated_at: 1582500000
        '401':
          description: Unauthorized request. Make sure that you provided the right credentials.
        '422':
          description: Validation error or a snippet with that name already exists.
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    type: array
                    description: Contains an array of error objects.
                    items:
                      type: object
                      properties:
                        detail:
                          type: string
                          description: The reason for the response.
                        status:
                          type: string
                          description: The HTTP status code.
                          example: '422'
                        source:
                          type: object
                          description: The field or path that caused the error.
                          properties:
                            pointer:
                              type: string
              examples:
                name_blank:
                  summary: Name empty or blank
                  value:
                    errors:
                    - detail: name cannot be blank
                      source:
                        pointer: /name
                      status: '422'
                value_blank:
                  summary: Value empty or blank
                  value:
                    errors:
                    - detail: value cannot be blank
                      source:
                        pointer: /value
                      status: '422'
                name_too_long:
                  summary: Name longer than 150 characters
                  value:
                    errors:
                    - detail: name cannot exceed 150 characters
                      source:
                        pointer: /name
                      status: '422'
                value_too_long:
                  summary: Value exceeds max length
                  value:
                    errors:
                    - detail: value cannot exceed 16000 characters
                      source:
                        pointer: /value
                      status: '422'
                snippet_reference:
                  summary: Value contains snippet reference
                  value:
                    errors:
                    - detail: Snippets cannot contain Liquid code referencing other snippets.
                      source:
                        pointer: /value
                      status: '422'
                name_exists:
                  summary: Name already exists
                  value:
                    errors:
                    - detail: A snippet with that name already exists
                      source:
                        pointer: /name
                      status: '422'
        '429':
          description: Your request is over the 10-per-second limit.
        '500':
          description: Internal server error (for example, render service failure when validating Liquid).
      x-codeSamples:
      - lang: json
        label: JSON
        source: "{\n  \"name\": \"address\",\n  \"value\": \"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"\n}"
      - lang: Shell + Curl
        source: "curl --request POST \\\n  --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  --url https://api.customer.io/v1/snippets \\\n  --header 'content-type: application/json' \\\n  --data '{\"name\":\"address\",\"value\":\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"}'"
      - lang: Node + Native
        source: "const http = require(\"https\");\n\nconst options = {\n  \"method\": \"POST\",\n  \"hostname\": \"api.customer.io\",\n  \"port\": null,\n  \"path\": \"/v1/snippets\",\n  \"headers\": {\n    \"content-type\": \"application/json\"\n  }\n};\n\nconst req = http.request(options, function (res) {\n  const chunks = [];\n\n  res.on(\"data\", function (chunk) {\n    chunks.push(chunk);\n  });\n\n  res.on(\"end\", function () {\n    const body = Buffer.concat(chunks);\n    console.log(body.toString());\n  });\n});\n\nreq.write(JSON.stringify({\n  name: 'address',\n  value: '<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111'\n}));\nreq.end();"
      - lang: Ruby + Native
        source: 'require ''uri''

          require ''net/http''

          require ''openssl''


          url = URI("https://api.customer.io/v1/snippets")


          http = Net::HTTP.new(url.host, url.port)

          http.use_ssl = true

          http.verify_mode = OpenSSL::SSL::VERIFY_NONE


          request = Net::HTTP::Post.new(url)

          request["content-type"] = ''application/json''

          request.body = "{\"name\":\"address\",\"value\":\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"}"


          response = http.request(request)

          puts response.read_body'
      - lang: Python + Python3
        source: 'import http.client


          conn = http.client.HTTPSConnection("api.customer.io")


          payload = "{\"name\":\"address\",\"value\":\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"}"


          headers = { ''content-type'': "application/json" }


          conn.request("POST", "/v1/snippets", payload, headers)


          res = conn.getresponse()

          data = res.read()


          print(data.decode("utf-8"))'
      - lang: Go + Native
        source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/snippets\"\n\n\tpayload := strings.NewReader(\"{\\\"name\\\":\\\"address\\\",\\\"value\\\":\\\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\\\"}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}"
    put:
      summary: Update snippets
      operationId: updateSnippets
      security:
      - Bearer-Auth: []
      description: In your payload, you'll pass a `name` and `value`. Snippet names are unique. If the snippet `name` does not exist, we'll create a new snippet. If the `name` exists, we'll update the existing snippet.
      tags:
      - Snippets
      requestBody:
        content:
          application/json:
            schema:
              x-scalar-ignore: true
              type: object
              description: Request body for creating or updating a snippet. Only `name` and `value` are accepted; `updated_at` is returned in responses only.
              required:
              - name
              - value
              properties:
                name:
                  type: string
                  maxLength: 150
                  description: The name of the snippet, must be unique. Trimmed of leading and trailing whitespace before storage.
                value:
                  type: string
                  description: The contents of the snippet (plain text or Liquid). Trimmed of leading and trailing whitespace before storage. Max length is environment-specific (default 16000).
              example:
                name: address
                value: <strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111
      responses:
        '200':
          description: Returns an array of `snippets`.
          content:
            application/json:
              schema:
                type: object
                properties:
                  snippet:
                    x-scalar-ignore: true
                    type: object
                    description: describes a piece of reusable content. You must provide a name for the snippet and the `value`—the content that appears in messages that use the snippet.
                    required:
                    - name
                    - value
                    properties:
                      name:
                        type: string
                        description: The name of the snippet, must be unique.
                      value:
                        type: string
                        description: The contents of the snippet.
                      updated_at:
                        type: integer
                        format: unix timestamp
                        description: The last date-time the snippet was updated.
                        readOnly: true
                    example:
                      name: address
                      value: <strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111
                      updated_at: 1582500000
        '400':
          description: The request is malformed.
        '429':
          description: Your request is over the 10-per-second limit.
      x-codeSamples:
      - lang: json
        label: JSON
        source: "{\n  \"name\": \"address\",\n  \"value\": \"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"\n}"
      - lang: Shell + Curl
        source: "curl --request PUT \\\n  --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  --url https://api.customer.io/v1/snippets \\\n  --header 'content-type: application/json' \\\n  --data '{\"name\":\"address\",\"value\":\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"}'"
      - lang: Node + Native
        source: "const http = require(\"https\");\n\nconst options = {\n  \"method\": \"PUT\",\n  \"hostname\": \"api.customer.io\",\n  \"port\": null,\n  \"path\": \"/v1/snippets\",\n  \"headers\": {\n    \"content-type\": \"application/json\"\n  }\n};\n\nconst req = http.request(options, function (res) {\n  const chunks = [];\n\n  res.on(\"data\", function (chunk) {\n    chunks.push(chunk);\n  });\n\n  res.on(\"end\", function () {\n    const body = Buffer.concat(chunks);\n    console.log(body.toString());\n  });\n});\n\nreq.write(JSON.stringify({\n  name: 'address',\n  value: '<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111'\n}));\nreq.end();"
      - lang: Ruby + Native
        source: 'require ''uri''

          require ''net/http''

          require ''openssl''


          url = URI("https://api.customer.io/v1/snippets")


          http = Net::HTTP.new(url.host, url.port)

          http.use_ssl = true

          http.verify_mode = OpenSSL::SSL::VERIFY_NONE


          request = Net::HTTP::Put.new(url)

          request["content-type"] = ''application/json''

          request.body = "{\"name\":\"address\",\"value\":\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"}"


          response = http.request(request)

          puts response.read_body'
      - lang: Python + Python3
        source: 'import http.client


          conn = http.client.HTTPSConnection("api.customer.io")


          payload = "{\"name\":\"address\",\"value\":\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\"}"


          headers = { ''content-type'': "application/json" }


          conn.request("PUT", "/v1/snippets", payload, headers)


          res = conn.getresponse()

          data = res.read()


          print(data.decode("utf-8"))'
      - lang: Go + Native
        source: "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/snippets\"\n\n\tpayload := strings.NewReader(\"{\\\"name\\\":\\\"address\\\",\\\"value\\\":\\\"<strong>My Company</strong></br>1234 Fake St<br/>Fake,NY<br/>10111\\\"}\")\n\n\treq, _ := http.NewRequest(\"PUT\", url, payload)\n\n\treq.Header.Add(\"content-type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}"
  /v1/snippets/{snippet_name}:
    servers:
    - url: https://api.customer.io
      description: This API uses bearer authorization, requiring a [token that you generate in the UI](https://fly.customer.io/settings/api_credentials?keyType=app).
    parameters:
    - name: snippet_name
      in: path
      required: true
      description: The name of a snippet.
      schema:
        type: string
    delete:
      summary: Delete a snippet
      operationId: deleteSnippet
      security:
      - Bearer-Auth: []
      description: Remove a snippet. You can only remove a snippet that is not in use. If your snippet is in use, you'll receive a `400` error.
      tags:
      - Snippets
      responses:
        '204':
          description: A successful delete operation returns no content.
        '400':
          description: The snippet is in use. You can't delete a snippet until you remove it from messages, templates, etc.
          content:
            application/json:
              schema:
                type: object
                properties:
                  errors:
                    description: Contains an array of error objects.
                    type: array
                    items:
                      type: object
                      properties:
                        detail:
                          type: string
                          description: Describes the error.
                          example: unable to delete snippet in use
                        status:
                          type: string
                          description: The HTTP status code.
                          example: '400'
        '404':
          description: The snippet does not exist.
        '429':
          description: Your request is over the 10-per-second limit.
      x-codeSamples:
      - lang: Shell + Curl
        source: "curl --request DELETE \\\n  --header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \\\n  --url https://api.customer.io/v1/snippets/{snippet_name}"
      - lang: Node + Native
        source: "const http = require(\"https\");\n\nconst options = {\n  \"method\": \"DELETE\",\n  \"hostname\": \"api.customer.io\",\n  \"port\": null,\n  \"path\": \"/v1/snippets/%7Bsnippet_name%7D\",\n  \"headers\": {}\n};\n\nconst req = http.request(options, function (res) {\n  const chunks = [];\n\n  res.on(\"data\", function (chunk) {\n    chunks.push(chunk);\n  });\n\n  res.on(\"end\", function () {\n    const body = Buffer.concat(chunks);\n    console.log(body.toString());\n  });\n});\n\nreq.end();"
      - lang: Ruby + Native
        source: 'require ''uri''

          require ''net/http''

          require ''openssl''


          url = URI("https://api.customer.io/v1/snippets/%7Bsnippet_name%7D")


          http = Net::HTTP.new(url.host, url.port)

          http.use_ssl = true

          http.verify_mode = OpenSSL::SSL::VERIFY_NONE


          request = Net::HTTP::Delete.new(url)


          response = http.request(request)

          puts response.read_body'
      - lang: Python + Python3
        source: 'import http.client


          conn = http.client.HTTPSConnection("api.customer.io")


          conn.request("DELETE", "/v1/snippets/%7Bsnippet_name%7D")


          res = conn.getresponse()

          data = res.read()


          print(data.decode("utf-8"))'
      - lang: Go + Native
        source: "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.customer.io/v1/snippets/%7Bsnippet_name%7D\"\n\n\treq, _ := http.NewRequest(\"DELETE\", url, nil)\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}"
components:
  securitySchemes:
    Bearer-Auth:
      type: http
      scheme: bearer
      description: 'The App API uses a bearer authentication scheme.


        You can generate a bearer token, known as an **App API Key**, with a defined scope in [your account settings](https://fly.customer.io/settings/api_credentials?keyType=app). [Learn more about bearer authorization in Customer.io](/accounts/settings/managing-credentials).

        '
    ServiceAccount-Auth:
      x-scalar-ignore: true
      type: http
      scheme: bearer
      bearerFormat: sa_live_
      description: 'Transactional send endpoints (`/v1/send/email`, `/v1/send/push`, `/v1/send/sms`, `/v1/send/in_app`, `/v1/send/inbox_message`) also accept a service-account bearer token, prefixed with `sa_live_`. Service-account tokens work across workspaces, so you must pass the target workspace as the `X-Workspace-Id` header on each request.


        Service-account tokens are intended for testing and one-off sends—for example, using the Customer.io CLI with an AI agent like Claude to verify that a transactional message renders correctly before wiring it into your production backend. **For the production integration that triggers the message from your application, use an App API Key instead**: it''s workspace-scoped, easier to rotate, and has a smaller blast radius.


        Service-account tokens are server-side credentials. Treat them like any API key—keep them in environment variables or a secret manager, and never embed them in client-side code, mobile apps, or other untrusted contexts.

        '
    bearerAuth:
      type: http
      scheme: bearer
      description: API key passed as a Bearer token