Save Payees as Contacts

Save a third-party payee once — with their bank account, mailing address, international account, card, or PPI — and reuse it across payout and collection rails.

A Contact is a saved, reusable third party you pay or collect from — a vendor, contractor, employee, or another business. You store their payout details once (a bank account, mailing address, international account, card, or Passport Payment ID), then reference the saved contact by id on every future transaction instead of re-entering details each time.

A single contact can bundle more than one payment instrument, so you can reach the same payee across different rails. To save the customer's own bank account, use External Accounts instead — Contacts are for third parties.

For the complete field list, jump to the Request reference.


How a Contact Works

  • Create the contact with one or more payment instruments — externalAccount, internationalExternalAccount, card, mailingAddress, or a ppi.
  • Verification runs per instrument. Bank-account instruments are OFAC-screened on the holder name (and validated like External Accounts); a ppi instrument is verified against an existing Passport account and is usable immediately.
  • Reference the contact id when you create a payout or collection. One saved contact serves many transactions.

Save a payee once and reuse it. Fewer re-keys means faster initiation, fewer errors, and cleaner reconciliation.


Base Path

Contacts are created under a customer:

Base pathDescription
/v1/customer/id/{customerId}/contactCustomer-owned contacts (by Passport ID)
/v1/customer/externalId/{customerExternalId}/contactCustomer-owned contacts (by program-manager externalId)

Every create, update, verify, and configuration request requires the PromiseMode header (NEVER for an immediate response, ALWAYS to defer processing).


Create Your First Contact

The fastest way to see it work: save a vendor's US bank account so you can pay them by ACH or wire later.

Request

POST /v1/customer/id/{customerId}/contact
PromiseMode: NEVER

{
  "externalId": "CON-EXT-0001",
  "name": "Acme Supplier",
  "contactType": "BUSINESS",
  "legalName": "Acme Supplier LLC",
  "externalAccount": [
    {
      "holderName": "Acme Supplier LLC",
      "holderType": "CORPORATE",
      "accountNumber": "123456789012",
      "routingNumber": "021000021",
      "wireRoutingNumber": "021000021",
      "type": "CHECKING"
    }
  ]
}

Response — 201 Created

Create returns 201 Created with an empty body; the new contact's ID is in the url (Location) response header. (With PromiseMode: ALWAYS, you get 202 Accepted and processing continues asynchronously.)

HTTP/1.1 201 Created
url: /v1/customer/id/{customerId}/contact/id/5501

Retrieve the contact to see its instruments and their verification status:

GET /v1/customer/id/{customerId}/contact/id/5501

{
  "resourceName": "contact",
  "url": "/v1/customer/id/{customerId}/contact/id/5501",
  "id": 5501,
  "externalId": "CON-EXT-0001",
  "name": "Acme Supplier",
  "contactType": "BUSINESS",
  "legalName": "Acme Supplier LLC",
  "externalAccount": [
    {
      "resourceName": "externalAccount",
      "id": 4000364,
      "holderName": "Acme Supplier LLC",
      "holderType": "CORPORATE",
      "accountNumberLast4": "9012",
      "routingNumber": "021000021",
      "status": "INACTIVE",
      "verification": { "ofacStatus": "PENDING_VERIFICATION" }
    }
  ]
}

Use externalId for safe retries

For Treasury, PCE treats the externalId in the request body as the idempotency key — there's no separate header. Send a unique externalId per contact; retrying with the same value creates it only once.


Scenarios

Save a payee by providing one or more instruments, then reference the contact on future transactions. Bank instruments are OFAC-screened; PPI instruments are usable immediately.

sequenceDiagram
    participant App as Your application
    participant PCE as PCE
    participant OFAC as OFAC Screening

    App->>PCE: POST /contact (name + instrument)
    PCE->>PCE: Field validation
    PCE-->>App: 201 Created (id in url header)
    alt Bank-account / card instrument
        PCE->>OFAC: Screen holder name
        OFAC-->>PCE: Cleared / Rejected
        PCE-->>App: Webhook — instrument ACTIVE or BLOCKED
    else PPI instrument
        PCE->>PCE: Verify PPI exists
        PCE-->>App: Instrument usable immediately
    end
    Note over App: Reference contact.id in future transactions

Before you begin (all scenarios)

  • Customer exists and is ACTIVE.
  • You have the payee's instrument details (bank account, mailing address, PPI, international account, or card).
  • Your webhook endpoint is subscribed to contact/external-account events (to track verification).

Scenario 1: Pay a Business by Bank Transfer (ACH / Wire)

Save a third-party US bank account for ACH or domestic wire payouts.

You'll also need: the payee's routing number, account number, account type, and holder type (CONSUMER / CORPORATE).

POST /v1/customer/id/{customerId}/contact
PromiseMode: NEVER

{
  "externalId": "contact-vendor-001",
  "name": "Acme Supplies",
  "contactType": "BUSINESS",
  "legalName": "Acme Supplies LLC",
  "externalAccount": [
    {
      "holderName": "Acme Supplies LLC",
      "holderType": "CORPORATE",
      "accountNumber": "987654321098",
      "routingNumber": "021000089",
      "wireRoutingNumber": "021000089",
      "type": "CHECKING"
    }
  ]
}

Scenario 2: Pay an Individual by Mailed Check

Save a mailing address for check payouts.

You'll also need: the recipient's name and a US mailing address.

POST /v1/customer/id/{customerId}/contact
PromiseMode: NEVER

{
  "externalId": "contact-check-002",
  "name": "Jane Doe",
  "contactType": "INDIVIDUAL",
  "firstName": "Jane",
  "lastName": "Doe",
  "mailingAddress": [
    {
      "name": "Jane Doe",
      "addressLine1": "100 Market St",
      "city": "San Jose",
      "state": "CA",
      "zip": "95113"
    }
  ]
}

Scenario 3: Pay a Payee with a Passport Account (PPI)

Save an internal payee by their Passport Payment ID for BOOK transfers. PPI instruments skip external validation and are usable immediately.

You'll also need: the payee's PPI. Confirm it first with the Verify PPI API.

POST /v1/customer/id/{customerId}/contact
PromiseMode: NEVER

{
  "externalId": "contact-ppi-003",
  "name": "Bright Tech",
  "contactType": "BUSINESS",
  "legalName": "Bright Tech Inc",
  "ppi": "brighttech@ppi"
}

Scenario 4: Pay a Recipient Abroad (International Wire)

Save an international bank account for cross-border payouts. Field rules follow International External Accounts (valid SWIFT code, accepted currency, holder address).

You'll also need: the SWIFT code, account number/IBAN, accepted currency, and holder address.

POST /v1/customer/id/{customerId}/contact
PromiseMode: NEVER

{
  "externalId": "contact-intl-004",
  "name": "Globex GmbH",
  "contactType": "BUSINESS",
  "legalName": "Globex GmbH",
  "internationalExternalAccount": [
    {
      "type": "CHECKING",
      "holderName": "Globex GmbH",
      "holderType": "CORPORATE",
      "accountNumber": "DE89370400440532013000",
      "swiftCode": "DEUTDEFF",
      "acceptedCurrency": ["EUR"],
      "purpose": "Services",
      "holderAddress": {
        "addressLine1": "Friedrichstrasse 100",
        "city": "Berlin",
        "country": "DE",
        "zip": "10117"
      }
    }
  ]
}

Scenario 5: Save a Payee's Card

Save a card instrument for the payee. A single-use token generated with the Passport SDK is preferred over raw PAN details.

You'll also need: the recipient's email (required for virtual-card delivery) and either a card token or full card details.

POST /v1/customer/id/{customerId}/contact
PromiseMode: NEVER

{
  "externalId": "contact-card-005",
  "name": "Sam Lee",
  "contactType": "INDIVIDUAL",
  "firstName": "Sam",
  "lastName": "Lee",
  "email": "[email protected]",
  "card": [
    { "token": "eyJjYXJkVHlwZS==" }
  ]
}

Verify a PPI

Before saving or paying a PPI-based payee, confirm the Passport Payment ID exists.

POST /v1/customer/id/{customerId}/contact/verifyPpi
PromiseMode: NEVER

{
  "ppi": "brighttech@ppi"
}

A 204 No Content response means the PPI exists and is valid (no body is returned). An invalid PPI returns 400.


Retrieve, List, and Manage Contacts


Payment Acceptance Configuration (optional)

You can attach payment-acceptance rules to a contact — for example, to constrain a method to an exact amount. Use the Add Contact Configurations API; read them back with Get Contact Configuration.

POST /v1/customer/id/{customerId}/contact/id/{contactId}/configuration
PromiseMode: NEVER

{
  "paymentAcceptanceCriteria": [
    {
      "method": ["MONEYGRAM"],
      "matchType": "EXACT",
      "amount": "1000.00"
    }
  ]
}

A successful call returns 204 No Content.


Request Reference

Contact core fields

ParameterRequiredTypeDescription
nameStringDisplay label for the contact
contactTypeConditionalStringINDIVIDUAL or BUSINESS
firstNameConditionalStringFor INDIVIDUAL contacts
lastNameConditionalStringFor INDIVIDUAL contacts
legalNameConditionalStringFor BUSINESS contacts
emailConditionalStringRequired for a virtual-card (card) payout. Format [email protected]
ppiConditionalStringPassport Payment ID of an internal payee
externalIdRecommendedStringYour reference ID; used as the idempotency key

Provide at least one payment instrument below (a contact can hold several).

Instrument: externalAccount[] (domestic bank account)

ParameterRequiredDescription
holderNameAccount holder name as on bank records
holderTypeCONSUMER or CORPORATE
accountNumberBank account number
routingNumber9-digit ACH routing number
typeSAVINGS or CHECKING
wireRoutingNumberOptional9-digit routing number for wires, if different
holderPhoneOptionalHolder phone number
holderAddressOptionalHolder address (addressLine1, city, state, zip)

Instrument: internationalExternalAccount[]

Field rules match International External Accounts: type, holderName, holderType, accountNumber, swiftCode, acceptedCurrency (array), holderAddress, and conditional internationalRoutingCode / purpose.

Instrument: mailingAddress[] (check)

ParameterRequiredDescription
addressLine1Street address (4–40 chars)
cityCity
stateTwo-character US state code
zip5- or 9-digit ZIP
nameOptionalName of the address owner
phoneOptionalPhone number

Instrument: card

ParameterRequiredDescription
tokenPreferredSingle-use token generated with the Passport SDK
cardNumberIf no token13–17 digit card number
expiryMonth / expiryYearIf no tokenmm / yyyy
cvvIf no tokenCard CVV
brandIf no tokenVISA, MASTERCARD, DISCOVER, AMERICAN_EXPRESS
holderNameIf no tokenCardholder name
billingAddress / avsOptionalBilling address and AVS details

Verification & Status

  • Bank-account and card instruments are OFAC-screened on the holder name and follow the same lifecycle as External Accounts: they start INACTIVE, become ACTIVE once screening and validation clear, and are BLOCKED if OFAC/validation fails. Each instrument in the retrieve response carries its own status and verification.ofacStatus.
  • PPI instruments are verified against an existing Passport account and are usable immediately.
  • Track verification with contact / external-account webhooks, or by retrieving the contact and checking each instrument's status.

Validation

When you submit the request, we validate:

CheckError if failed
name present400 — Required field
At least one valid instrument provided400 — Missing instrument
Bank instrument has accountNumber, routingNumber, holderName, holderType, type400 — Missing field
SWIFT code valid (international)400 — Invalid routing code
PPI exists (PPI instrument)400 — Invalid PPI
Contact exists and not deleted (on retrieve/update)404 — Not found
Contact belongs to the path customer403 — Owner mismatch

Best Practices

PracticeDescription
Set a unique externalIdUsed as the idempotency key — retries never create duplicates
Verify a PPI before savingConfirms the internal payee exists
Use a card token, not raw PANSDK-generated single-use tokens avoid handling card data
Reuse contacts for repeat paymentsFaster initiation, fewer errors, cleaner reconciliation
Store the contact idRequired to pay, retrieve, update, or delete
Monitor instrument statusA payout can only use an ACTIVE bank instrument

Related


Did this page help you?
.readme-logo { display: none !important; }