payments-ai Merchant API

Partner onboarding and merchant team operations — create sub-merchants and assign active members of your team onto merchants you manage.

Operations 4

POST /v1/public-api/merchants Create merchant #
GET /v1/public-api/merchants/{merchantId} Get merchant #
PATCH /v1/public-api/merchants/{merchantId} Update merchant website URL #
POST /v1/public-api/merchants/{merchantId}/members Assign member #

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/payments-ai:payments-ai-merchant-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

payments-ai-merchant-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Payments AI MoR Public Merchant API
  version: 1.0.0
  description: Merchant Public API, partner onboarding, and buyer checkout endpoints. Authenticate every call with a Merchant API Key (pai_test_* / pai_live_*). The same key reaches its own merchant resources and those of any sub-merchant it has onboarded via POST /v1/public-api/merchants.
servers:
- url: https://sandbox.mor.payments.ai/api
  description: Sandbox API
tags:
- name: Merchant
  description: Partner onboarding and merchant team operations — create sub-merchants and assign active members of your team onto merchants you manage.
paths:
  /v1/public-api/merchants:
    post:
      operationId: PublicApiMerchants_create
      description: Creates a sub-merchant parented to the calling key's own merchant. The parent is always derived from the Bearer key, never from the request body. A merchant that already has a parent cannot itself become a parent — calling this with a sub-merchant's own key returns 409.
      parameters: []
      responses:
        '201':
          description: The request has succeeded and a new resource has been created as a result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiCreateMerchantResponse'
      tags:
      - Merchant
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicApiCreateMerchantRequest'
      summary: Create merchant
  /v1/public-api/merchants/{merchantId}:
    get:
      operationId: PublicApiMerchants_get
      description: 'Reads whether a merchant has an owner and how far it is through activation. `merchantId` must be your own merchant or a sub-merchant you created. Any other id returns 403, including one that does not exist, so a key cannot probe for merchant ids outside its scope. After you deliver a join URL, poll this route or subscribe to the `merchant.owner_attached` webhook instead of reminting the link. Auth: Merchant API key, or user OAuth credential with `merchant:read` · tenant `{merchantId}` · any team member · 401 `auth.invalid_token` · 403 `auth.insufficient_scope`, `merchant.access_forbidden`.'
      parameters:
      - name: merchantId
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiGetMerchantResponse'
      tags:
      - Merchant
      security:
      - MerchantApiKeyAuth: []
      - UserOAuthCredentialAuth: []
      summary: Get merchant
    patch:
      operationId: PublicApiMerchantWebsiteUrl_updateWebsiteUrl
      parameters:
      - name: merchantId
        in: path
        required: true
        schema:
          type: string
      responses:
        '200':
          description: The request has succeeded.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiUpdateMerchantWebsiteUrlResponse'
      tags:
      - Merchant
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicApiUpdateMerchantWebsiteUrlRequest'
      summary: Update merchant website URL
  /v1/public-api/merchants/{merchantId}/members:
    post:
      operationId: PublicApiMerchantMembers_assign
      parameters:
      - name: merchantId
        in: path
        required: true
        schema:
          type: string
      responses:
        '201':
          description: The request has succeeded and a new resource has been created as a result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiAssignMerchantMemberResponse'
      tags:
      - Merchant
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicApiAssignMerchantMemberRequest'
      summary: Assign member
components:
  schemas:
    PublicApiCreateMerchantRequest:
      type: object
      required:
      - name
      - email
      properties:
        name:
          type: string
          maxLength: 145
          description: Business name displayed to customers. `'s Merchant` is appended when stored. Capped at 145 so the provider company title fits.
        email:
          type: string
          format: email
          description: Owner email. If a user with this email already exists, they are assigned as Owner; otherwise the merchant is created without a membership and `ownerAttached` is false.
        phone:
          type: string
          pattern: ^\+[1-9]\d{1,14}$
          description: Optional E.164 phone. If omitted, the merchant provides it during KYC.
        merchantId:
          type: string
          description: 'Optional client-supplied UUID v7 idempotency key. Re-submitting the same id with the same details is safe and returns `created: false`.'
        websiteUrl:
          type: string
          maxLength: 255
          pattern: ^https://
          format: uri
          description: Optional HTTPS website URL for the sub-merchant. Used to validate checkout `returnUrl` hosts. Must start with `https://`. Max 255 characters.
        allowedReturnHosts:
          type: array
          items:
            type: string
          maxItems: 20
          description: 'Optional. Exact hostnames, besides the `websiteUrl` host and the checkout host, that a checkout `returnUrl` may point to. Each entry is a bare hostname such as `shop.example.com`: no scheme, path, port, wildcard, IP address or `localhost`. Entries are lowercased, converted to punycode and de-duplicated. Matching is exact: a listed host does not cover its subdomains. At most 20 entries. Sending the list replaces the stored list; `[]` clears it. An invalid entry returns 400 naming the entry. On idempotent replay the list is applied only when the stored list is still empty; a replay with a different list returns 409.'
    PublicApiMerchantActivation:
      type: object
      required:
      - status
      - identityVerification
      properties:
        status:
          type: string
          enum:
          - not_provisioned
          - pending
          - verification_pending
          - active
          description: 'Go-live progress: `not_provisioned` (no payment account yet), `pending` (payment account created, go-live not recorded), `verification_pending` (go-live recorded, identity verification not complete), `active` (go-live recorded and identity verified). Follow the seller''s identity verification with `identityVerification`.'
        identityVerification:
          type: string
          enum:
          - not_started
          - pending
          - in_review
          - verified
          - rejected
          description: Identity verification (KYC) state. `not_started` until the owner starts identity verification in the dashboard.
    PublicApiGetMerchantResponse:
      type: object
      required:
      - merchantId
      - ownerAttached
      - activation
      - allowedReturnHosts
      properties:
        merchantId:
          type: string
        ownerAttached:
          type: boolean
          description: True once the merchant has an active owner — attached at create, claimed by the seller through the join URL, or assigned with `POST .../members`. To learn about a join URL claim without polling, subscribe to the `merchant.owner_attached` webhook.
        activation:
          $ref: '#/components/schemas/PublicApiMerchantActivation'
        allowedReturnHosts:
          type: array
          items:
            type: string
          description: Hosts a checkout `returnUrl` may use besides the `websiteUrl` host and the checkout host. Empty when none are set.
    PublicApiUpdateMerchantWebsiteUrlRequest:
      type: object
      properties:
        websiteUrl:
          type: string
          maxLength: 255
          pattern: ^https://
          format: uri
          description: HTTPS website URL for the merchant. Its hostname is always allowed as a checkout `returnUrl` host.
        allowedReturnHosts:
          type: array
          items:
            type: string
          maxItems: 20
          description: 'Exact hostnames, besides the `websiteUrl` host and the checkout host, that a checkout `returnUrl` may point to. Each entry is a bare hostname such as `shop.example.com`: no scheme, path, port, wildcard, IP address or `localhost`. Entries are lowercased, converted to punycode and de-duplicated. Matching is exact: a listed host does not cover its subdomains. At most 20 entries. Sending the list replaces the stored list; `[]` clears it. An invalid entry returns 400 naming the entry.'
      description: Send `websiteUrl`, `allowedReturnHosts` or both.
    PublicApiCreateMerchantResponse:
      type: object
      required:
      - merchantId
      - created
      - ownerAttached
      properties:
        merchantId:
          type: string
        created:
          type: boolean
          description: True on first create; false when this `merchantId` had already been provisioned with matching details.
        ownerAttached:
          type: boolean
          description: True when the owner email matched an existing user and was assigned the `owner` role. False when the email is unknown to PAI — the response then also carries `joinUrl` / `joinUrlExpiresAt`, a claim link the partner delivers to the seller. PAI does not email the seller directly. Alternatively use `POST .../members` to copy an existing active member of your team onto the sub-merchant after create, or have the owner sign up before create. Read the current value later with `GET /v1/public-api/merchants/{merchantId}`.
        joinUrl:
          type: string
          description: Owner-claim join URL. Present only when `ownerAttached` is false. Deliver to the seller so they can sign up (or in) and claim ownership. Regenerate via `POST /v1/public-api/merchants/{merchantId}/join-link` if the seller loses or expires it.
        joinUrlExpiresAt:
          type: string
          format: date-time
          description: Expiration of the `joinUrl` (7 days after issuance). Present only when `joinUrl` is present.
    PublicApiAssignMerchantMemberResponse:
      type: object
      required:
      - userId
      - email
      - role
      - status
      properties:
        userId:
          type: string
        email:
          type: string
        role:
          $ref: '#/components/schemas/PublicApiTeamRole'
        status:
          allOf:
          - $ref: '#/components/schemas/PublicApiTeamMemberStatus'
          description: Always `active` after a successful assign.
    PublicApiUpdateMerchantWebsiteUrlResponse:
      type: object
      properties:
        websiteUrl:
          type: string
          description: Present when the request set `websiteUrl`.
        allowedReturnHosts:
          type: array
          items:
            type: string
          description: 'Present when the request set `allowedReturnHosts`: the stored, normalised list.'
      description: Echoes the fields sent in the request, with their stored values.
    PublicApiAssignMerchantMemberRequest:
      type: object
      required:
      - email
      - role
      properties:
        email:
          type: string
          format: email
        role:
          $ref: '#/components/schemas/PublicApiTeamRole'
    PublicApiTeamRole:
      type: string
      enum:
      - owner
      - admin
      - editor
      - viewer
    PublicApiTeamMemberStatus:
      type: string
      enum:
      - active
  securitySchemes:
    UserOAuthCredentialAuth:
      type: http
      scheme: Bearer
      description: 'Signed-in user OAuth credential (`pai_mcp_*`) issued through the dashboard consent screen for this API: the authorization and token requests name the RFC 8707 resource `<API_URL>/v1/public-api` (ADR-0020). Credentials issued for the MCP server, or for no resource, are rejected with 401 `auth.invalid_token` and `WWW-Authenticate: Bearer resource_metadata="<API_URL>/.well-known/oauth-protected-resource/v1/public-api", error="invalid_token"`. Valid on the environment that issued it only. Each operation that accepts it names one required permission; a missing permission is 403 `auth.insufficient_scope` with `WWW-Authenticate: Bearer error="insufficient_scope", scope="<permission>"`. A merchant outside the user''s active memberships is 403 `merchant.access_forbidden`; a team role below the operation''s minimum is 403 `team.role_forbidden`.'
    MerchantApiKeyAuth:
      type: http
      scheme: Bearer
      description: 'Merchant API key from Developer Tools → API Keys. Example: `Authorization: Bearer pai_test_...`. Also accepted for any active sub-merchant this key''s own merchant created.'