> ## Documentation Index
> Fetch the complete documentation index at: https://docs.myproceeds.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a paywall

> Paywalls always settle to the tenant's own wallet — the merchant
wallet is set automatically to the tenant's primary wallet and is
not accepted as a parameter. Slugs must be unique within the parent
service (`serviceId` + `slug`).




## OpenAPI

````yaml /openapi.yaml post /v1/paywalls
openapi: 3.0.3
info:
  title: myproceeds API
  version: 1.1.0
  description: |
    Public REST API for the myproceeds (x402) commerce platform.

    Tenants use this API to programmatically manage their Services and
    Paywalls. Authentication is via API keys generated from the dashboard.

    ## Authentication

    Send the API key in one of two ways:

      Authorization: Bearer mpk_<64 hex chars>
      X-Api-Key: mpk_<64 hex chars>

    Key format: `mpk_` prefix followed by 64 lowercase hex characters
    (32 random bytes). The raw key is only shown once at creation and
    cannot be recovered later.

    ## Scopes

    Each key carries a set of scopes that determine which endpoints it
    can call:

      - `services:read`     — read services
      - `services:write`    — create/update/delete services (implies read)
      - `paywalls:read`     — read paywalls
      - `paywalls:write`    — create/update/delete paywalls (implies read)
      - `transactions:read` — read payment transactions
      - `events:read`       — read analytics events

    Use `GET /v1/me` to validate a key and inspect the tenant and scopes
    it carries.

    ## Secret handling

    Secret material — service `authConfig` values and paywall custom header
    values — is always masked as `"***"` in API responses. Field names (keys)
    are returned so you can see what is configured; the plaintext values are
    never exposed by the public API.

    ## Rate limits

    Each API key may make up to 1000 requests per 60-second window.
    When exceeded the API responds with `429 Too Many Requests` and a
    `Retry-After` header indicating seconds to wait.

    ## Response envelope

    Successful responses return:

      { "data": ..., "meta": { "requestId": "...", "timestamp": "..." } }

    Lists additionally include `meta.pagination`:

      { "total": N, "limit": L, "offset": O, "hasMore": bool }

    Errors return a `meta.requestId` you can quote to support, which
    correlates with the server log line:

      { "error": "message", "code": "MACHINE_CODE", "details": ...,
        "meta": { "requestId": "...", "timestamp": "..." } }
servers:
  - url: https://api.myproceeds.xyz
    description: Current environment
security:
  - ApiKeyAuth: []
tags:
  - name: Identity
    description: >-
      API-key authenticated endpoint to validate a key and read its
      tenant/scopes
  - name: Services
    description: API-key authenticated CRUD for tenant services
  - name: Paywalls
    description: API-key authenticated CRUD for tenant paywalls
  - name: Data
    description: API-key authenticated read-only access to transactions and analytics
  - name: System
    description: Unauthenticated service health endpoints
paths:
  /v1/paywalls:
    post:
      tags:
        - Paywalls
      summary: Create a paywall
      description: |
        Paywalls always settle to the tenant's own wallet — the merchant
        wallet is set automatically to the tenant's primary wallet and is
        not accepted as a parameter. Slugs must be unique within the parent
        service (`serviceId` + `slug`).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaywallCreate'
      responses:
        '201':
          description: Paywall created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Envelope'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Paywall'
        '400':
          $ref: '#/components/responses/ValidationError'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Slug conflict within the service
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - ApiKeyAuth:
            - paywalls:write
components:
  schemas:
    PaywallCreate:
      type: object
      required:
        - slug
        - name
        - targetType
        - price
        - currency
        - fulfillmentMode
      properties:
        slug:
          type: string
          minLength: 1
          maxLength: 50
          pattern: ^[a-z0-9._-]+$
        name:
          type: string
          minLength: 1
          maxLength: 100
        description:
          type: string
        targetType:
          type: string
          enum:
            - PROXY
            - ROUTE
        targetUrl:
          type: string
          format: uri
        targetRoute:
          type: string
        price:
          type: string
        currency:
          type: string
          enum:
            - USDC
        network:
          $ref: '#/components/schemas/NetworkId'
        networks:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/NetworkId'
        fulfillmentMode:
          type: string
          enum:
            - PROXY
            - SIGNED_URL
        timeout:
          type: integer
          minimum: 30000
          maximum: 3600000
        headers:
          type: array
          items:
            type: object
            required:
              - key
              - value
            properties:
              key:
                type: string
                pattern: ^[a-zA-Z0-9-_]+$
              value:
                type: string
                maxLength: 1000
        allowedMethods:
          type: array
          minItems: 1
          items:
            type: string
            enum:
              - GET
              - POST
              - PUT
              - PATCH
        queryParams:
          type: array
          items:
            type: object
            required:
              - key
              - value
            properties:
              key:
                type: string
              value:
                type: string
        serviceId:
          type: string
        enabled:
          type: boolean
        cacheRules:
          type: object
          additionalProperties: true
    Envelope:
      type: object
      required:
        - data
        - meta
      properties:
        data: {}
        meta:
          $ref: '#/components/schemas/Meta'
    Paywall:
      type: object
      properties:
        id:
          type: string
        slug:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        targetType:
          type: string
          enum:
            - PROXY
            - ROUTE
        targetUrl:
          type: string
          nullable: true
          format: uri
        routePattern:
          type: string
          nullable: true
        price:
          type: string
          description: Amount in USDC smallest unit (string for precision)
        currency:
          type: string
          enum:
            - USDC
        network:
          $ref: '#/components/schemas/NetworkId'
        networks:
          type: array
          items:
            $ref: '#/components/schemas/NetworkId'
        merchantWallet:
          type: string
          pattern: ^0x[a-fA-F0-9]{40}$
        facilitatorUrl:
          type: string
          format: uri
        timeout:
          type: integer
        validityWindow:
          type: integer
        allowedMethods:
          type: array
          items:
            type: string
            enum:
              - GET
              - POST
              - PUT
              - PATCH
        fulfillmentMode:
          type: string
          enum:
            - PROXY
            - SIGNED_URL
        enabled:
          type: boolean
        headers:
          type: array
          nullable: true
          description: |
            Configured custom request headers. Values are masked as `"***"` in
            API responses — only the header keys are returned.
          items:
            type: object
            properties:
              key:
                type: string
              value:
                type: string
                example: '***'
        queryParams:
          type: array
          nullable: true
          items:
            type: object
            properties:
              key:
                type: string
              value:
                type: string
        serviceId:
          type: string
          nullable: true
        userId:
          type: string
          nullable: true
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    Error:
      type: object
      required:
        - error
        - code
        - meta
      properties:
        error:
          type: string
          description: Human-readable message
        code:
          type: string
          description: Machine-readable code
          enum:
            - INVALID_API_KEY
            - KEY_REVOKED
            - KEY_EXPIRED
            - KEY_INACTIVE
            - INSUFFICIENT_SCOPE
            - IP_NOT_ALLOWED
            - RATE_LIMITED
            - NOT_FOUND
            - FORBIDDEN
            - VALIDATION_ERROR
            - CONFLICT
            - KEY_LIMIT_REACHED
            - SSRF_BLOCKED
            - ALREADY_REVOKED
            - INVALID_WALLET
            - INVALID_SERVICE
            - BETA_LIMIT_PAYWALLS
            - BETA_LIMIT_SERVICES
            - INTERNAL_ERROR
            - DATABASE_ERROR
        details:
          description: Optional machine-readable detail (e.g. Zod issues)
        meta:
          $ref: '#/components/schemas/Meta'
    NetworkId:
      type: string
      description: |
        Supported blockchain network identifier. The value must match the
        owning Service / Paywall `mode`: pass a **testnet** identifier when
        `mode` is `testnet`, and a **mainnet** identifier when `mode` is
        `mainnet`.
      example: base-sepolia
      enum:
        - arc-testnet
        - base-sepolia
        - hyperevm-testnet
        - tempo-testnet
        - base
        - hyperevm
        - tempo
    Meta:
      type: object
      properties:
        requestId:
          type: string
        timestamp:
          type: string
          format: date-time
  responses:
    ValidationError:
      description: Request validation failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: API key missing, invalid, revoked, or expired
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Valid API key required
            code: INVALID_API_KEY
    Forbidden:
      description: Insufficient scope, IP not allowed, or not the resource owner
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Api-Key
      description: |
        API key in format `mpk_<64 hex chars>`. Can alternatively be sent as
        `Authorization: Bearer mpk_...`.

````