Skip to content

✨ server: add wallet provisioning endpoint#949

Open
aguxez wants to merge 2 commits intosignaturefrom
server-provisioning
Open

✨ server: add wallet provisioning endpoint#949
aguxez wants to merge 2 commits intosignaturefrom
server-provisioning

Conversation

@aguxez
Copy link
Copy Markdown
Contributor

@aguxez aguxez commented Apr 10, 2026

Closes #440


Open with Devin

Summary by CodeRabbit

  • New Features

    • Added a wallet provisioning endpoint allowing authenticated users to retrieve provisioning details (card ID and time-based secret) for an eligible card.
  • Tests

    • Added comprehensive tests for successful provisioning, processor error mappings, deleted/missing card, missing external association, and missing credential scenarios.
  • Chores

    • Added a changeset declaring a patch release documenting the new wallet provisioning endpoint.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 10, 2026

🦋 Changeset detected

Latest commit: e5b5193

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@exactly/server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@aguxez aguxez force-pushed the server-provisioning branch from 7de9bc2 to 1d0aa0f Compare April 10, 2026 09:27
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new authenticated GET /wallet endpoint that loads a credential's ACTIVE|FROZEN card, calls Panda for processor details, returns processorCardId/timeBasedSecret, adds a Panda utility, tests covering success and error mappings, and adds a changeset for a patch release.

Changes

Cohort / File(s) Summary
Wallet Endpoint
server/api/card.ts
New authenticated GET /wallet route: reads credentialId from cookie, loads credential (pandaId + first `ACTIVE
Panda Utility
server/utils/panda.ts
Added exported getProcessorDetails(cardId: string) which GETs /issuing/cards/${cardId}/processorDetails and validates/returns { processorCardId, timeBasedSecret }.
Tests
server/test/api/card.test.ts
Added wallet test suite seeding credentials/cards and asserting: success for active/frozen cards (200 with processor details and stub verification), Panda error mappings (404→404 { code: "no card" }, 5xx→500), and credential/panda/card absence responses (500/403/404 as appropriate).
Release Metadata
.changeset/chilly-suns-dress.md
New changeset declaring a patch release for @exactly/server referencing the wallet provisioning endpoint.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant API as GET /wallet
    participant DB as Database
    participant Panda as Panda API

    Client->>API: GET /wallet (credentialId cookie)
    API->>DB: Load credential (pandaId, first ACTIVE|FROZEN card)
    alt no credential
        DB-->>API: not found
        API-->>Client: 500 { code: "no credential" }
    else credential missing pandaId
        DB-->>API: credential (no pandaId)
        API-->>Client: 403 { code: "no panda" }
    else no eligible card
        DB-->>API: credential (no eligible card)
        API-->>Client: 404 { code: "no card" }
    else credential + card found
        DB-->>API: credential + cardId
        API->>Panda: GET /issuing/cards/{cardId}/processorDetails
        alt processor details found
            Panda-->>API: { processorCardId, timeBasedSecret }
            API-->>Client: 200 { cardId, cardSecret }
        else processor 404
            Panda-->>API: 404
            API-->>Client: 404 { code: "no card" }
        else other error
            Panda-->>API: error
            API-->>Client: 500 (error)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • cruzdanilo
  • nfmelendez
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'add wallet provisioning endpoint' accurately and directly describes the main change: a new authenticated GET /wallet endpoint for wallet provisioning. It is specific, clear, and concise without unnecessary details.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch server-provisioning

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@aguxez aguxez marked this pull request as draft April 10, 2026 09:27
devin-ai-integration[bot]

This comment was marked as resolved.

gemini-code-assist[bot]

This comment was marked as resolved.

@sentry
Copy link
Copy Markdown

sentry Bot commented Apr 10, 2026

Codecov Report

❌ Patch coverage is 91.83673% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.75%. Comparing base (adf8f7d) to head (e5b5193).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
server/api/card.ts 91.83% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           signature     #949      +/-   ##
=============================================
+ Coverage      71.32%   73.75%   +2.42%     
=============================================
  Files            228      229       +1     
  Lines           8447     9284     +837     
  Branches        2716     3097     +381     
=============================================
+ Hits            6025     6847     +822     
+ Misses          2188     2174      -14     
- Partials         234      263      +29     
Flag Coverage Δ
e2e 73.75% <91.83%> (+22.99%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@aguxez aguxez force-pushed the server-provisioning branch 3 times, most recently from af7c987 to 9495bf1 Compare April 10, 2026 13:10
coderabbitai[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from 9495bf1 to 0975d4d Compare April 10, 2026 13:46
coderabbitai[bot]

This comment was marked as resolved.

@aguxez aguxez marked this pull request as ready for review April 10, 2026 16:12
@aguxez aguxez force-pushed the server-provisioning branch from 0975d4d to 0ed88f7 Compare April 13, 2026 08:27
coderabbitai[bot]

This comment was marked as resolved.

chatgpt-codex-connector[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from 0ed88f7 to ba4376c Compare April 13, 2026 09:21
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
server/test/api/card.test.ts (1)

867-869: ⚠️ Potential issue | 🟡 Minor

Use Panda in the mocked ServiceError for consistency.

"Rain" works, but using the real provider label keeps test fixtures closer to production behavior.

Suggested fix
-      vi.spyOn(panda, "getProcessorDetails").mockRejectedValueOnce(new ServiceError("Rain", 500, "internal error"));
+      vi.spyOn(panda, "getProcessorDetails").mockRejectedValueOnce(new ServiceError("Panda", 500, "internal error"));

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7e528c82-bb28-42c9-8cd9-b0f075ed5b87

📥 Commits

Reviewing files that changed from the base of the PR and between 0ed88f7 and ba4376c.

📒 Files selected for processing (4)
  • .changeset/chilly-suns-dress.md
  • server/api/card.ts
  • server/test/api/card.test.ts
  • server/utils/panda.ts

sentry[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from ba4376c to 2f6644b Compare April 15, 2026 08:39
coderabbitai[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch 2 times, most recently from 9662eac to b49e535 Compare April 21, 2026 14:10
chatgpt-codex-connector[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from b49e535 to 1cf381c Compare April 21, 2026 14:40
devin-ai-integration[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from c9cf016 to 184fdc9 Compare April 27, 2026 09:01
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from 184fdc9 to 61f0b3e Compare April 27, 2026 10:02
devin-ai-integration[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from 61f0b3e to ced86c6 Compare April 27, 2026 10:34
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from ced86c6 to 5b50548 Compare April 28, 2026 07:50
devin-ai-integration[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from 5b50548 to 6ae30c0 Compare April 28, 2026 09:47
chatgpt-codex-connector[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from 6ae30c0 to 4fafee0 Compare April 28, 2026 10:56
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4fafee0c5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread server/api/card.ts Outdated
if (status === "DELETED") throw new Error("card deleted");
const [{ expirationMonth, expirationYear, limit }, pan, user, pin, provisioning] = await Promise.all([
getCard(id),
getSecrets(id, c.req.valid("header").sessionid),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard stale PAN lookup in provisioning path

The new stale-card mapping only wraps getProcessorDetails(), but getSecrets() in the same Promise.all is still unhandled. When Panda has already removed a card, getSecrets() can return 404 first, which rejects the whole request and bypasses the intended { code: "no card" } response for scope=provisioning, producing an unexpected server error instead. This makes stale-card behavior timing-dependent in the new provisioning flow.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is uncertain right now. on purpose, the only provisioning-specific call that maps these failures to 404 { code: "no card" } is getProcessorDetails().

so i’m leaving this thread open as the current design boundary rather than resolving it as addressed.

devin-ai-integration[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch 9 times, most recently from 1be83a0 to d981d2d Compare April 30, 2026 23:16
@aguxez aguxez changed the base branch from main to signature May 1, 2026 13:49
@aguxez aguxez force-pushed the server-provisioning branch from d981d2d to 7589266 Compare May 1, 2026 13:50
devin-ai-integration[bot]

This comment was marked as resolved.

@aguxez aguxez force-pushed the server-provisioning branch from 7589266 to 1ce4184 Compare May 1, 2026 14:08
@aguxez aguxez force-pushed the server-provisioning branch from 1ce4184 to e5b5193 Compare May 1, 2026 14:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

server: push provisioning

1 participant