Plunk Contacts API

Manage contacts and their subscription state.

Business capability
Customer Data Management BC-420.10

Operations 10

Each operation below carries the questions people ask an LLM about it and the instructions they give an agent to run it. Generated by API Evangelist overlay

GET /contacts List contacts · List contacts #
Ask an LLM
“Which contacts are on my Plunk mailing list?”
“Can I list only the contacts who have unsubscribed?”
Tell an agent
List my contacts, 100 per page.
Show contacts whose email contains {search}.
POST /contacts Create or upsert a contact by email · Create or update contact #
Ask an LLM
“How do I add a new contact to my list?”
“If the email already exists, will adding a contact update it instead of duplicating it?”
Tell an agent
Add {email} as a contact.
Upsert contact {email} with subscribed {subscribed} and data {data}.
PUT /contacts Update a contact by id in the request body · Update a contact #
Ask an LLM
“Is there an update endpoint where the contact id goes in the body rather than the URL?”
“Can I set a contact's metadata with the older PUT contacts call?”
Tell an agent
Using the body-id PUT endpoint, set contact {id} subscribed to {subscribed}.
Via PUT /contacts, replace the metadata of contact {id} with {data}.
DELETE /contacts Delete a contact by id in the request body · Delete a contact #
Ask an LLM
“Can I delete a contact by sending its id in the request body?”
“Is there a delete call on the bare contacts path without an id in the URL?”
Tell an agent destructive · confirm first
Using the body-id DELETE /contacts call, permanently delete contact {id}.
Send contact id {id} in the body to erase that contact.
GET /contacts/{id} Get a single contact · Get contact #
Ask an LLM
“How do I look up one contact's details by their id?”
“What data is stored on a particular contact?”
Tell an agent
Fetch contact {id}.
Show me the subscription state and data for contact {id}.
PATCH /contacts/{id} Patch a contact's email, subscription or data · Update contact #
Ask an LLM
“Can I change a contact's email address?”
“What happens if I change a contact's email to one another contact already uses?”
Tell an agent
Change the email of contact {id} to {email}.
Patch contact {id} data with {data}.
DELETE /contacts/{id} Permanently delete a contact by URL id · Delete contact #
Ask an LLM
“How do I permanently remove a contact when I have its id for the URL path?”
“Is deleting a contact reversible?”
Tell an agent destructive · confirm first
Permanently delete contact {id} via its own contact URL.
Erase the contact whose id is {id} from the URL path.
GET /contacts/count Count all contacts · Count contacts #
Ask an LLM
“How many contacts are in my project in total?”
“What's the size of my whole contact list?”
Tell an agent
Count my contacts.
Tell me the total number of contacts in the project.
POST /contacts/subscribe Subscribe a contact · Subscribe a contact #
Ask an LLM
“How do I resubscribe someone who previously opted out?”
“Is there a one-step call to mark a contact as subscribed?”
Tell an agent
Subscribe contact {id}.
Opt contact {id} back into emails.
POST /contacts/unsubscribe Unsubscribe a contact · Unsubscribe a contact #
Ask an LLM
“How do I unsubscribe a contact who asked to stop getting emails?”
“Can I opt someone out without deleting their contact record?”
Tell an agent
Unsubscribe contact {id}.
Opt contact {id} out of all emails.

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/plunk:plunk-contacts-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

plunk-contacts-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Plunk Contacts API
  version: '1.0'
  description: 'Operations tagged Contacts across 2 of this provider''s published API definitions: plunk-api-openapi.json, plunk-openapi.yml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://next-api.useplunk.com
  description: Production server
- url: https://api.useplunk.com/v1
  description: Plunk hosted API
tags:
- name: Contacts
  description: Contact management operations
paths:
  /contacts:
    get:
      tags:
      - Contacts
      summary: List contacts
      description: Get a paginated list of contacts with cursor-based pagination.
      operationId: listContacts
      parameters:
      - $ref: '#/components/parameters/Limit'
      - $ref: '#/components/parameters/Cursor'
      - name: search
        in: query
        schema:
          type: string
        description: Case-insensitive substring match on email.
      - name: subscribed
        in: query
        schema:
          type: boolean
        description: Filter by subscription state. Omit to return both subscribed and unsubscribed contacts.
      - name: sort
        in: query
        schema:
          type: string
          enum:
          - email
          - createdAt
          default: createdAt
        description: Column to sort by. Unrecognised values fall back to `createdAt`.
      - $ref: '#/components/parameters/SortDirection'
      responses:
        '200':
          description: List of contacts
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Contact'
                  cursor:
                    type: string
                    nullable: true
                    description: Cursor for the next page. Pass this back as the `cursor` query parameter to fetch the next page.
                  hasMore:
                    type: boolean
                  total:
                    type: integer
                    description: Total count. Only populated on the first page (when no `cursor` is supplied); subsequent pages return `0` to avoid the recount cost.
        '401':
          $ref: '#/components/responses/Unauthorized'
      security:
      - ApiKeyAuth: []
    post:
      tags:
      - Contacts
      summary: Create or update contact
      description: Create a new contact or update existing (upsert by email)
      operationId: createContact
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - email
              properties:
                email:
                  type: string
                  format: email
                subscribed:
                  type: boolean
                  default: true
                data:
                  type: object
                  additionalProperties: true
            example:
              email: user@example.com
              subscribed: true
              data:
                firstName: John
                lastName: Doe
                plan: premium
      responses:
        '200':
          description: Contact updated
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/Contact'
                - type: object
                  properties:
                    _meta:
                      type: object
                      properties:
                        isNew:
                          type: boolean
                        isUpdate:
                          type: boolean
        '201':
          description: Contact created
          content:
            application/json:
              schema:
                allOf:
                - $ref: '#/components/schemas/Contact'
                - type: object
                  properties:
                    _meta:
                      type: object
                      properties:
                        isNew:
                          type: boolean
                        isUpdate:
                          type: boolean
        '400':
          description: '`email` was not supplied.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LegacyError'
              example:
                error: Email is required
        '401':
          $ref: '#/components/responses/Unauthorized'
      security:
      - ApiKeyAuth: []
    put:
      operationId: updateContact
      tags:
      - Contacts
      summary: Update a contact
      description: Updates the subscription state and/or metadata of an existing contact.
      security:
      - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateContactRequest'
            example:
              id: contact_123
              data:
                plan: enterprise
      responses:
        '200':
          description: The updated contact.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact_2'
        '401':
          $ref: '#/components/responses/Unauthorized_2'
        '404':
          $ref: '#/components/responses/NotFound_2'
    delete:
      operationId: deleteContact
      tags:
      - Contacts
      summary: Delete a contact
      description: Permanently deletes a contact by id.
      security:
      - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - id
              properties:
                id:
                  type: string
                  description: The id of the contact to delete.
            example:
              id: contact_123
      responses:
        '200':
          description: The deleted contact.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact_2'
        '401':
          $ref: '#/components/responses/Unauthorized_2'
        '404':
          $ref: '#/components/responses/NotFound_2'
    servers:
    - url: https://next-api.useplunk.com
      description: Production server
  /contacts/{id}:
    get:
      tags:
      - Contacts
      summary: Get contact
      description: Get a single contact by ID
      operationId: getContact
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: Contact details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
      security:
      - ApiKeyAuth: []
    patch:
      tags:
      - Contacts
      summary: Update contact
      description: Update an existing contact's email, subscription state, or `data` fields.
      operationId: patchContactsById
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  description: Change the contact's email address. Returns 409 if another contact in the project already uses this email.
                subscribed:
                  type: boolean
                  description: Update subscription state. Flipping this fires `contact.subscribed` or `contact.unsubscribed`.
                data:
                  type: object
                  additionalProperties: true
                  description: Patch contact data. `null` deletes a key, empty strings are ignored, primitives are stored. Reserved keys are silently filtered out.
      responses:
        '200':
          description: Contact updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: An existing contact already uses the email you're trying to set.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
      - ApiKeyAuth: []
      x-operation-id-source: normalized
      x-operation-id-original: updateContact
    delete:
      tags:
      - Contacts
      summary: Delete contact
      description: Permanently delete a contact
      operationId: deleteContactsById
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      responses:
        '204':
          description: Contact deleted successfully (no content returned)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
      security:
      - ApiKeyAuth: []
      x-operation-id-source: normalized
      x-operation-id-original: deleteContact
    servers:
    - url: https://next-api.useplunk.com
      description: Production server
  /contacts/count:
    get:
      operationId: getContactCount
      tags:
      - Contacts
      summary: Count contacts
      description: Returns the total number of contacts in the project.
      security:
      - bearerAuth: []
      responses:
        '200':
          description: The contact count.
          content:
            application/json:
              schema:
                type: object
                properties:
                  count:
                    type: integer
                    example: 4096
        '401':
          $ref: '#/components/responses/Unauthorized_2'
    servers:
    - url: https://api.useplunk.com/v1
      description: Plunk hosted API
  /contacts/subscribe:
    post:
      operationId: subscribeContact
      tags:
      - Contacts
      summary: Subscribe a contact
      description: Sets a contact's subscription state to subscribed.
      security:
      - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactSubscriptionRequest'
            example:
              id: contact_123
      responses:
        '200':
          description: The updated contact.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact_2'
        '401':
          $ref: '#/components/responses/Unauthorized_2'
        '404':
          $ref: '#/components/responses/NotFound_2'
    servers:
    - url: https://api.useplunk.com/v1
      description: Plunk hosted API
  /contacts/unsubscribe:
    post:
      operationId: unsubscribeContact
      tags:
      - Contacts
      summary: Unsubscribe a contact
      description: Sets a contact's subscription state to unsubscribed.
      security:
      - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ContactSubscriptionRequest'
            example:
              id: contact_123
      responses:
        '200':
          description: The updated contact.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Contact_2'
        '401':
          $ref: '#/components/responses/Unauthorized_2'
        '404':
          $ref: '#/components/responses/NotFound_2'
    servers:
    - url: https://api.useplunk.com/v1
      description: Plunk hosted API
components:
  parameters:
    Limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
      description: Maximum items per page. Values above 100 are clamped to 100.
    Cursor:
      name: cursor
      in: query
      schema:
        type: string
      description: Pagination cursor. Pass the `cursor` returned by the previous page.
    SortDirection:
      name: dir
      in: query
      schema:
        type: string
        enum:
        - asc
        - desc
        default: desc
      description: Sort direction. Unrecognised values fall back to the default.
  schemas:
    FieldError:
      type: object
      properties:
        field:
          type: string
          description: Dot-path of the offending field, e.g. `attachments.0.filename`.
        message:
          type: string
        code:
          type: string
          description: Validation issue code, e.g. `invalid_type`, `too_big`, `reserved_event`.
        received:
          description: The value that was received, when available.
    LegacyError:
      type: object
      description: Flat error shape returned by the hand-validated create/update endpoints (`POST /contacts`, `POST /templates`, `POST /segments`) for missing required fields. Unlike the rest of the API these return `400` with a bare `error` string rather than the standard envelope. Errors raised deeper in those same endpoints (404, 409, domain verification) still use the standard `Error` envelope.
      properties:
        error:
          type: string
    Error:
      type: object
      properties:
        success:
          type: boolean
          enum:
          - false
        error:
          type: object
          properties:
            code:
              type: string
              description: Machine-readable error code, e.g. `VALIDATION_ERROR`, `INVALID_API_KEY`, `IDEMPOTENCY_KEY_REUSED`.
            message:
              type: string
            statusCode:
              type: integer
            requestId:
              type: string
              description: Correlation ID for this request. Include it when contacting support.
            errors:
              type: array
              items:
                $ref: '#/components/schemas/FieldError'
              description: Field-level detail, present on validation failures.
            details:
              type: object
              additionalProperties: true
              description: Additional error context.
            suggestion:
              type: string
              description: Hint for fixing the request.
        timestamp:
          type: string
          format: date-time
    Contact:
      type: object
      properties:
        id:
          type: string
          description: Unique contact identifier
        email:
          type: string
          format: email
          description: Contact email address
        subscribed:
          type: boolean
          description: Subscription status
        data:
          type: object
          description: Custom contact data fields
          additionalProperties: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    ContactSubscriptionRequest:
      type: object
      required:
      - id
      properties:
        id:
          type: string
          description: The id of the contact.
    CreateContactRequest:
      type: object
      required:
      - email
      properties:
        email:
          type: string
          format: email
        subscribed:
          type: boolean
          default: true
        data:
          type: object
          additionalProperties: true
    UpdateContactRequest:
      type: object
      required:
      - id
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        subscribed:
          type: boolean
        data:
          type: object
          additionalProperties: true
    Error_2:
      type: object
      properties:
        success:
          type: boolean
          example: false
        code:
          type: integer
        error:
          type: string
        message:
          type: string
        time:
          type: integer
    Contact_2:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        subscribed:
          type: boolean
        data:
          type: object
          additionalProperties: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
  responses:
    NotFound:
      description: The requested resource does not exist in this project.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            success: false
            error:
              code: INVALID_API_KEY
              message: Invalid secret API key. This endpoint requires a secret key (sk_*), not a public key.
              statusCode: 401
              requestId: 8f14e45f-ceea-467a-9575-1f0f38e0b1c2
            timestamp: '2025-01-15T10:30:00.000Z'
    ValidationError:
      description: The request body failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error_2'
    NotFound_2:
      description: The requested resource was not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error_2'
    Unauthorized_2:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error_2'
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: 'API Key authentication. The project is automatically derived from the key.


        **`/v1/track` requires a public key (`pk_*`)** — it is the one endpoint intended for client-side use, and a secret key is rejected there with `401`.


        **Every other endpoint requires a secret key (`sk_*`)** and rejects public keys with `401`.


        So the two key types are not interchangeable in either direction: pick the key that matches the endpoint you are calling.'
    bearerAuth:
      type: http
      scheme: bearer
      description: Plunk API key passed as a Bearer token. Use a secret key (sk_) for most endpoints; the /track endpoint additionally accepts a public key (pk_).
x-refined-from:
- plunk-api-openapi.json
- plunk-openapi.yml
x-ext-urls: {}