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

# Add a Processor Key

> Register a processor API key and choose which borrowers and payment types it takes

# Add a Processor Key

Rightfoot collects payments through your own merchant accounts at a [supported payment processor](#supported-processors). Register the API key of each account you hold, and tell Rightfoot which borrowers and which payment types it should be used for.

Paste the key once. Rightfoot stores it in a vault the moment the request is accepted; from then on every response shows only its last four characters, and the key itself is never returned.

If the person holding the keys would rather not call the API, the same flow is in the portal — see [Processor Keys in the Portal](/api-reference/payments/processor-keys-portal).

## Supported processors

Rightfoot works with the processor you already hold merchant accounts at. Register keys from any processor in this list; every endpoint on these pages behaves the same regardless of which one issued the key.

| Processor                              | Payment types   | Where to get the key                                      |
| -------------------------------------- | --------------- | --------------------------------------------------------- |
| [Payliance](https://www.payliance.com) | ACH, debit card | An API key for each merchant account, issued by Payliance |

<Note>
  Using a processor that is not listed? Ask Rightfoot about adding it. Nothing about how you enroll borrowers changes when a processor is added — only where the keys come from.
</Note>

## Default keys and tagged keys

Which key a payment goes through is decided by two things you set when you add it.

<CardGroup cols={2}>
  <Card title="Default key" icon="star">
    Used for every borrower you enroll **without** a `merchant_ref`. Set `is_default: true`. You can hold one default per payment type — ACH, debit card, or a single key that covers both.
  </Card>

  <Card title="Tagged key" icon="tag">
    Used only for borrowers you enroll **with** that tag. Set `merchant_ref` to a short slug such as `acme-nv`, and send the same value as `merchant_ref` when you [enroll](/api-reference/payments/create-payment-enrollments) those borrowers.
  </Card>
</CardGroup>

A key is one or the other, never both — a request with `is_default: true` and a `merchant_ref` is rejected. A key with neither is stored but not used for anything until you [promote it](/api-reference/payments/update-payment-connection#make-a-key-the-default).

<Note>
  **Tags are permanent.** Borrowers already enrolled under a tag would silently move to a different merchant account if the tag could change, so `merchant_ref` is fixed once saved. The key behind a tag is not — [replace it](/api-reference/payments/update-payment-connection#replace-a-key) any time and the tag stays.
</Note>

## One default per payment type

`rail_scope` says which payment types a key can take: `ach`, `card` (debit card), or `both`. It is required and has no default, because a key used for a payment type its merchant account was not set up for fails at the processor rather than here.

You can hold one default key per `rail_scope`. When a payment type is covered by both a `both` default and a type-specific default, the type-specific one wins — a dedicated ACH key takes the ACH payments, and the `both` key keeps covering debit card.

<Warning>
  A payment type with no default key skips every borrower enrolled without a tag. [List your keys](/api-reference/payments/list-payment-connections) to see which types are uncovered in `missing_default_rails`.
</Warning>

<Tip>
  One tag can hold one key per `rail_scope`, so `acme-nv` may have both an ACH key and a debit-card key if that merchant account is split by payment type at the processor.
</Tip>

## When a request is rejected

Conflicts are checked before the key is stored, so a rejected request leaves nothing behind. Send it again once corrected.

| Status | When                                                                                                                  |
| ------ | --------------------------------------------------------------------------------------------------------------------- |
| `400`  | A required field is missing, `merchant_ref` is not a valid tag, or `is_default` and `merchant_ref` were sent together |
| `409`  | A default key for that `rail_scope` already exists, or that tag already has a key for that `rail_scope`               |

The `error.message` in the response says which — for example `A default key for ACH already exists` or `Tag 'acme-nv' already has an ACH key`.


## OpenAPI

````yaml POST /v1/payment_connections
openapi: 3.1.0
info:
  title: Rightfoot API
  description: >-
    Submit a batch of authorizers for balance checks, retrieve processed
    balances, and check the status of a batch.
  version: 0.3.0-alpha
servers:
  - url: https://api.rightfoot.com
security:
  - BearerAuth: []
tags:
  - name: General Availability
    description: |
      **General Availability** indicates that the endpoint is production-ready.
  - name: Early Access
    description: >
      **Early Access** indicates that the endpoint is available for early access
      customers and is being actively refined.
  - name: In Development
    description: >
      **In Development** indicates that the endpoint is currently being built
      and will be available in an upcoming release.
paths:
  /v1/payment_connections:
    post:
      tags:
        - In Development
      summary: Add a processor key
      description: >
        Register one API key from a supported payment processor (currently

        Payliance). Rightfoot stores the key in a vault the moment the request

        is accepted and never returns it — every later response shows only its

        last four characters.


        A key is either the **default** for the payment types in `rail_scope`

        (`is_default: true`), or **tagged** with a `merchant_ref` that you send
        as

        `merchant_ref` when you enroll a borrower. It cannot be both. A key with

        neither is stored but not used until you promote it.


        Conflicts are checked before the key is stored, so a rejected request

        leaves nothing behind.
      operationId: create_payment_connection
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PaymentConnectionCreateRequest'
            examples:
              default_key:
                summary: Default key for both payment types
                value:
                  api_key: a1b2c3d4e5f6a7b8c9d0e1f2a3b4b6a0
                  label: Main key
                  rail_scope: both
                  is_default: true
              tagged_key:
                summary: Tagged ACH key
                value:
                  api_key: f6e5d4c3b2a1f6e5d4c3b2a1f6e5d2f4
                  label: Nevada ACH
                  rail_scope: ach
                  merchant_ref: acme-nv
      responses:
        '201':
          description: The key was stored.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentConnection'
              example:
                id: 02623289-b33a-4d42-9e08-4a9a849c9c84
                label: Nevada ACH
                merchant_ref: acme-nv
                rail_scope: ach
                is_default: false
                key_last4: d2f4
                last_poll_at: null
                access_scope: lender_admins
                created_at: '2026-08-28T15:04:37Z'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                missing_rail_scope:
                  summary: rail_scope not sent
                  value:
                    status: error
                    status_code: 400
                    error:
                      code: BAD_REQUEST
                      message: 'Validation error: body.rail_scope: Field required'
                      timestamp: '2026-08-28T15:04:37Z'
                      suggestion: Check request parameters and body.
                default_with_tag:
                  summary: is_default and merchant_ref sent together
                  value:
                    status: error
                    status_code: 400
                    error:
                      code: BAD_REQUEST
                      message: >-
                        Validation error: body: Value error, Default keys cannot
                        carry a merchant_ref — a default key is the one used
                        when an enrollment names no tag
                      timestamp: '2026-08-28T15:04:37Z'
                      suggestion: Check request parameters and body.
                invalid_tag:
                  summary: merchant_ref is not a valid tag
                  value:
                    status: error
                    status_code: 400
                    error:
                      code: BAD_REQUEST
                      message: >-
                        Validation error: body.merchant_ref: String should match
                        pattern '^[a-z0-9](?:[a-z0-9_-]{0,126}[a-z0-9])?$'
                      timestamp: '2026-08-28T15:04:37Z'
                      suggestion: Check request parameters and body.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: Conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorResponse'
              examples:
                default_exists:
                  summary: A default key for that rail_scope already exists
                  value:
                    status: error
                    status_code: 409
                    error:
                      code: CONFLICT
                      message: A default key for ACH already exists
                      timestamp: '2026-08-28T15:04:37Z'
                      suggestion: ''
                tag_and_rail_exist:
                  summary: That tag already has a key for that rail_scope
                  value:
                    status: error
                    status_code: 409
                    error:
                      code: CONFLICT
                      message: Tag 'acme-nv' already has an ACH key
                      timestamp: '2026-08-28T15:04:37Z'
                      suggestion: ''
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  schemas:
    PaymentConnectionCreateRequest:
      type: object
      required:
        - api_key
        - label
        - rail_scope
      properties:
        api_key:
          type: string
          minLength: 1
          description: >
            The API key your processor issued for one of your merchant accounts.
            Stored

            in a vault as soon as the request is accepted and never returned —

            responses carry only `key_last4`.
        label:
          type: string
          minLength: 1
          maxLength: 80
          description: |
            A name you will recognize, shown in the Rightfoot portal. Cosmetic —
            change it any time.
        rail_scope:
          type: string
          enum:
            - ach
            - card
            - both
          description: |
            The payment types this key can take: `ach`, `card` (debit card), or
            `both` when one merchant account covers both. Required — there
            is no default, because a key used for a payment type its merchant
            account was not set up for fails at the processor rather than here.
        is_default:
          type: boolean
          default: false
          description: >
            Make this the default key for the payment types in `rail_scope` —
            the

            key used for every borrower enrolled without a `merchant_ref`. One

            default per `rail_scope`. Cannot be combined with `merchant_ref`.
        merchant_ref:
          type: string
          pattern: ^[a-z0-9](?:[a-z0-9_-]{0,126}[a-z0-9])?$
          description: >
            A tag that enrollments name to settle to this key: send the same
            value

            as `merchant_ref` on `POST /v1/payment_enrollments`. Lowercase
            letters,

            digits, `-` and `_`; 1–128 characters; must start and end with a
            letter

            or digit. Fixed once saved. One tag can hold one key per
            `rail_scope`,

            so an ACH key and a debit-card key may share a tag.
    PaymentConnection:
      type: object
      description: One registered key. Never includes the key itself.
      properties:
        id:
          type: string
          format: uuid
          description: Use this to update or delete the key.
        label:
          type: string
          description: The name you gave the key.
        merchant_ref:
          type:
            - string
            - 'null'
          description: |
            The tag enrollments name to settle to this key, or `null` for a
            default or unused key.
        rail_scope:
          type: string
          enum:
            - ach
            - card
            - both
          description: The payment types this key can take.
        is_default:
          type: boolean
          description: Whether this is the default key for its `rail_scope`.
        key_last4:
          type:
            - string
            - 'null'
          description: The last four characters of the stored key, to tell keys apart.
        last_poll_at:
          type:
            - string
            - 'null'
          format: date-time
          description: |
            When Rightfoot last read payment results through this key. `null`
            until the first read.
        access_scope:
          type: string
          description: >-
            Reserved for a future permissions setting. Always `lender_admins`
            today.
        created_at:
          type: string
          format: date-time
          description: When the key was added.
    ApiErrorResponse:
      type: object
      properties:
        status:
          type: string
          description: Status of the error, either "error" or "success"
        status_code:
          type: integer
          description: HTTP status code of the error
        error:
          type: object
          properties:
            code:
              type: string
              description: Error code (e.g., "RESOURCE_NOT_FOUND")
            message:
              type: string
              description: Detailed error message.
            details:
              type: string
              description: Additional details about the error
            timestamp:
              type: string
              format: date-time
              description: Time the error occurred
            suggestion:
              type: string
              description: Suggested action to resolve the error
        documentation_url:
          type: string
          format: uri
          description: URL to the documentation for the error
  responses:
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            status: error
            status_code: 401
            error:
              code: UNAUTHORIZED
              message: Invalid API key provided.
              timestamp: '2024-09-16T12:01:00Z'
              suggestion: Please check your API key.
            documentation_url: https://api.rightfoot.com/docs
    InternalServerError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ApiErrorResponse'
          example:
            status: error
            status_code: 500
            error:
              code: INTERNAL_SERVER_ERROR
              message: An unexpected error occurred while retrieving the balances.
              timestamp: '2024-09-16T12:11:00Z'
              suggestion: >-
                Please try again later. If the problem persists, contact our
                support team.
            documentation_url: https://api.rightfoot.com/docs
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >
        Authentication to the API is performed via Bearer Token Authentication.
        Provide your API key as the bearer token in the Authorization header.


        All API requests must be made over HTTPS. Calls made over plain HTTP
        will fail. API requests without authentication will also fail.

````