Skip to content

Agreements – Retrieve User Agreements

When should I use this?

Use this flow whenever a signed-in user needs a consolidated list of agreements they created or joined: dashboards, recent activity views, or any post-login screen that must show ongoing deals, pending actions, or archived work.

Purpose

Expose the agreements visible to the authenticated user so clients can build list views, highlight pending obligations, and deep-link into agreement details without duplicating backend filtering logic. The endpoint returns PAYCIFI’s indexed agreement summaries and participant metadata; on-chain funding, validation, arbitration, and payout events settle independently on DShare and are reconciled asynchronously by the backend.

Preconditions

  • A valid PAYCIFI session. The API inspects the optional Authorization: Bearer <accessToken> header via the populateUser middleware and rejects malformed or expired tokens.
  • The userId path parameter MUST belong to the authenticated user. The backend cross-checks the token and rejects any attempt to read another user’s agreements.
  • The user MUST be a participant (payer, provider, or arbitrator) in the agreements to see them; non-participant agreements are always excluded.

Client Responsibilities

  • Ensure the userId in the request path matches the signed-in account; mismatches are rejected with an authorization error.
  • Supply role-aware UI hints (e.g., owner vs participant) based on isOwner, selfParticipantType, and userStatus fields returned by the API.
  • Cache or paginate results client-side if needed; the backend does not provide pagination parameters.

API Flow

  1. Request: GET /api/v1/agreements/user/:userId?status=<optional> with an Authorization header. The optional status query must match an agreement_statuses.label value (e.g., pending, funded, completed).
  2. Server visibility rules: The controller delegates to AgreementsService.getAgreementsSummaryByUserId, which joins participants to keep only agreements where userId appears in any role. Agreements the user archived via user_agreement_preferences (is_archived = true) are automatically excluded, regardless of status.
  3. Sorting & shaping: Results are ordered by acceptance_deadline ascending and returned as summary objects containing:
  4. Agreement metadata: id, title, description, network, creationDate, currency, totalAmount, status, arbitrationStatus, deadlines.
  5. Role context: ownerUserId, isOwner, selfParticipantType, userStatus, providersEmails.
  6. Payer snapshot: nested payer object (id, userId, name, email, phone, additionalInfo, status, owner).
  7. Arbitrator name when present.

Example Request

GET /api/v1/agreements/user/3f6f6b4f-9c7d-4b9b-9f5a-43b0d4c2f101?status=pending
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Example Response

[
  {
    "id": "d9b6da1a-432c-47d8-8b0d-9ac01aa4f1ce",
    "creationDate": "2025-01-04T11:22:03.145Z",
    "title": "Design Sprint Retainer",
    "description": "4-week design sprint with Nova Studio",
    "network": "polygon",
    "currency": "USDC",
    "totalAmount": 12000,
    "status": "pending",
    "arbitrationStatus": null,
    "acceptanceDeadline": 1736371200,
    "completionDeadline": 1738972800,
    "ownerUserId": "3f6f6b4f-9c7d-4b9b-9f5a-43b0d4c2f101",
    "isOwner": true,
    "selfParticipantType": "payer",
    "userStatus": "pending",
    "arbitratorName": null,
    "providersEmails": [
      "studio@nova.io"
    ],
    "payer": {
      "id": "f0629825-ea62-4a79-83e0-020b4b3f07c1",
      "userId": "3f6f6b4f-9c7d-4b9b-9f5a-43b0d4c2f101",
      "name": "Acme Corp",
      "email": "payer@acme.com",
      "phone": "+1-415-555-1212",
      "additionalInfo": "Finance desk",
      "participantType": "payer",
      "owner": true,
      "status": "pending"
    }
  },
  {
    "id": "9b7a9b7d-3341-4a8f-babc-2d0da1290333",
    "creationDate": "2024-12-15T08:44:11.621Z",
    "title": "Post-Production Package",
    "description": "Footage cleanup and delivery",
    "network": "ethereum",
    "currency": "USDC",
    "totalAmount": 4200,
    "status": "funded",
    "arbitrationStatus": "none",
    "acceptanceDeadline": 1734556800,
    "completionDeadline": 1737062400,
    "ownerUserId": "a2d912c5-3de4-42cf-a306-1d8731e7f19a",
    "isOwner": false,
    "selfParticipantType": "provider",
    "userStatus": "accepted",
    "arbitratorName": "Global Escrow Partners",
    "providersEmails": [
      "studio@nova.io",
      "sound@mixlab.fm"
    ],
    "payer": {
      "id": "a1304859-3c9a-49a0-8d3d-a8ae9e01d2ef",
      "userId": "a2d912c5-3de4-42cf-a306-1d8731e7f19a",
      "name": "Helios Ventures",
      "email": "payables@helios.vc",
      "phone": null,
      "additionalInfo": null,
      "participantType": "payer",
      "owner": false,
      "status": "funded"
    }
  }
]

Response Handling

  • Empty array: The user is not part of any agreement (or archived all of them). Display a zero-state and allow creation or invitation flows.
  • Partial visibility: Use isOwner and selfParticipantType to tailor what actions are surfaced. The API never exposes agreements where the user is not listed as a participant.
  • Navigation: Use the returned id to fetch full details via GET /api/v1/agreements/:agreementId, and reference the Escrow Protocol documentation (/protocol/using-the-escrow/) for lifecycle rules, funding, and on-chain fund movement.

Error Codes

HTTP errorCode When it occurs
400 missing-userId userId path parameter is absent.
500 agreements-retrieval-controller-error Unexpected failure inside the controller when fetching agreements.
500 agreementIds-retrieval-service-error Database failure while assembling the agreement summary.
  • GET /api/v1/agreements/user/:userId — agreement summary list (this flow).
  • GET /api/v1/agreements/:agreementId — full agreement detail for drill-down views.