P2P Payments

Overview

P2P (peer-to-peer) payments let one consumer send funds directly to another consumer within your partner network — no external bank accounts or card networks involved. Both the sender and receiver must hold a secured-card account (or secured-card subledger account) managed by your partner.

Common use cases:

  • Splitting bills between users
  • Gifting or rewarding another user on your platform
  • Intra-network fund transfers initiated by your application

Token scope required: api:write or api:purchase:write


Prerequisites

  • Valid OAuth 2.0 Bearer token (see Authentication)
  • Both consumers must have active secured-card accounts on your partner network
  • The sending consumer must have sufficient available balance
  • P2P payments must be enabled for your partner configuration

How It Works

Partner App Upwardli API CRB (Core Banking)
│ │ │
│ POST /v2/payments/p2p/ │ │
│─────────────────────────>│ │
│ │ Validate accounts │
│ │ Check balance │
│ │ Check velocity limit │
│ │ │
│ │ Create ledger entry │
│ │─────────────────────────>│
│ │ │
│ │ Submit to XPay │
│ │─────────────────────────>│
│ │ │
│ 201 { id, status } │ │
│<─────────────────────────│ │
│ │ │
│ │ Webhook: Payment.P2P.Created
│<─────────────────────────│ │
│ │ │
│ │ Webhook: Payment.P2P.Completed (async)
│<─────────────────────────│ │

Payment statuses

StatusMeaning
pendingPayment submitted and in process
postedFunds settled — transfer complete
pending_reviewPayment held for compliance review (velocity limit reached)
errorSubmission failed; contact support if it persists
canceledPayment was canceled
returnedPayment was returned by the receiving side

Compliance velocity hold

Upwardli enforces a daily velocity limit of 2 P2P transfers per consumer per 24-hour window (counting both sends and receives). When a consumer exceeds this limit, the payment is created with status pending_review instead of being rejected. Your application receives the normal 201 response with status: "pending_review".

A Payment.P2P.Created webhook is not sent for held payments. Once an Upwardli compliance agent reviews and approves the payment, it transitions to pending and proceeds normally, triggering the webhook at that point.


API Endpoints

Base URLs

Production: https://api.upwardli.com
Sandbox: https://api-sandbox.upwardli.com

1. Create a P2P Payment

Endpoint

POST /v2/payments/p2p/

Authentication

Authorization: Bearer <token>

Request body

FieldTypeRequiredDescription
originating_account_idUUIDYesExternal ID of the sending consumer’s account
receiving_account_idUUIDYesExternal ID of the receiving consumer’s account
amountfloatYesTransfer amount in USD. Minimum 1.00. Maximum set by your partner configuration.
descriptionstringNoOptional memo visible to both parties

The memo field is not accepted on P2P payments and will cause a validation error if included.

Example request

$curl -X POST https://api.upwardli.com/v2/payments/p2p/ \
> -H "Authorization: Bearer <token>" \
> -H "Content-Type: application/json" \
> -d '{
> "originating_account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
> "receiving_account_id": "7cb94a21-1a3b-4891-9e12-6d1f5a2bc099",
> "amount": 25.00,
> "description": "Splitting dinner"
> }'

Response — 201 Created

1{
2 "id": "a1b2c3d4-0000-4000-8000-000000000001",
3 "originating_account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
4 "receiving_account_id": "7cb94a21-1a3b-4891-9e12-6d1f5a2bc099",
5 "amount": 25.00,
6 "status": "pending",
7 "description": "Splitting dinner"
8}

Compliance-held response (same 201, different status):

1{
2 "id": "a1b2c3d4-0000-4000-8000-000000000002",
3 "originating_account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
4 "receiving_account_id": "7cb94a21-1a3b-4891-9e12-6d1f5a2bc099",
5 "amount": 25.00,
6 "status": "pending_review",
7 "description": "Splitting dinner"
8}

Full API reference

Create P2P Payment →


2. Retrieve a P2P Payment

Endpoint

GET /v2/payments/p2p/{id}/

Path parameters

ParameterTypeDescription
idUUIDThe id returned when the payment was created

Example request

$curl https://api.upwardli.com/v2/payments/p2p/a1b2c3d4-0000-4000-8000-000000000001/ \
> -H "Authorization: Bearer <token>"

Response — 200 OK

1{
2 "id": "a1b2c3d4-0000-4000-8000-000000000001",
3 "originating_account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
4 "receiving_account_id": "7cb94a21-1a3b-4891-9e12-6d1f5a2bc099",
5 "amount": 25.00,
6 "status": "posted",
7 "description": "Splitting dinner"
8}

Retrieve returns a 404 for any payment that does not belong to your partner — this is intentional and prevents information leakage.

Full API reference

Get P2P Payment →


3. List P2P Payments

Returns a paginated list of all P2P payments across every consumer on your partner network.

Endpoint

GET /v2/payments/p2p/

Query parameters

ParameterTypeDefaultDescription
pageinteger1Page number
page_sizeinteger20Results per page

Example request

$curl "https://api.upwardli.com/v2/payments/p2p/?page=1&page_size=20" \
> -H "Authorization: Bearer <token>"

Response — 200 OK

1{
2 "count": 42,
3 "next": "https://api.upwardli.com/v2/payments/p2p/?page=2&page_size=20",
4 "previous": null,
5 "results": [
6 {
7 "id": "a1b2c3d4-0000-4000-8000-000000000001",
8 "originating_account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
9 "receiving_account_id": "7cb94a21-1a3b-4891-9e12-6d1f5a2bc099",
10 "amount": 25.00,
11 "status": "posted",
12 "description": "Splitting dinner"
13 }
14 ]
15}

Full API reference

List P2P Payments →


Webhooks

Subscribe to P2P payment events to track payment lifecycle in real time.

EventWhen it fires
Payment.P2P.CreatedPayment successfully submitted and in process
Payment.P2P.CompletedFunds settled — transfer complete
Payment.P2P.FailedSubmission or settlement failed
Payment.P2P.CanceledPayment canceled (typically via admin action)

Payment.P2P.Created is not sent for payments in pending_review status. It fires only once the payment has been approved and submitted to the core banking network.

Register your webhook endpoint to receive these events:

Webhook Registration →

Full Webhook Event Catalog →


Error Reference

Validation errors (422)

These are returned in the response body when the request fails business-rule validation.

error_codeCauseHow to resolve
feature_unavailableP2P payments are not enabled for your partner configurationContact Upwardli to enable P2P
invalid_amountAmount is below $1.00 or exceeds your partner’s configured limitAdjust the amount
invalid_account_typesOne or both accounts are not secured-card accountsConfirm the account external IDs are correct
invalid_account_pairOriginating and receiving accounts are the sameUse two distinct accounts
not_foundOne or both accounts do not belong to your partnerVerify the account IDs belong to consumers on your network
insufficient_fundsSender’s available balance is below the requested amountAsk the sender to fund their account first
invalid_accountNo payment card found for the originating accountThe account may not be fully provisioned

Other errors

HTTP statusCause
404Payment ID not found or does not belong to your partner
401Missing or invalid Bearer token
403Token scope does not include api:write or api:purchase:write
500Unexpected server error — open a support ticket