Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Key input field notes:
- `--approval-detail` — optional JSON object (MCP/agent) or JSON string (CLI) with approval details for delegated flows. Required fields: `approved_at` (unix timestamp int), `approval_method` (`click`|`programmatic`|`voice`), `app_name`, `external_user_id`. Optional: `ip_address`, `user_agent`, `device_type` (`mobile`|`web`), `agent_log_id`, `external_user_name`, `external_session_id`, `authentication_method` (`biometric_face`|`biometric_fingerprint`|`passkey`). Sent as `approval_details` in the API request body.
- `card` credentials include `billing_address` (name, line1, line2, city, state, postal_code, country) and `valid_until` (ISO date string — when the card expires/stops working)
- `--output-file <path>` on `retrieve` or `create` writes full card credentials to a local file (0600 permissions) and redacts card data in stdout. `--force` allows overwriting an existing file.
- `create` also accepts an undocumented `--expires-at <unix_seconds>` to override the default 12-hour spend request expiration (3 hours to 7 days in the future). It's deliberately excluded from `--schema`/`--llms-full` output and from README/SKILL.md: it's gated to an allow-list of OAuth clients server-side, and most callers get a 400 (`"expires_at is not supported for this client"`) if they try it — don't document or suggest it to general agents.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I know this requires a backend change, but I wonder if we should make this a delta rather than an absolute timestamp - I remember hearing that agents have a hard time generating these timestamps as opposed to specifying something like "5 mins"

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.

I tested it a couple times and don't seem to have issues with this

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.

I will keep it as is and update if we run into problem


### mpp pay

Expand Down
52 changes: 52 additions & 0 deletions packages/cli/src/__tests__/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,58 @@ describe('production mode', () => {
expect(sentBody.metadata).toBeUndefined();
});

it('sends expires_at in POST body when --expires-at is used', async () => {
setNextResponse(200, BASE_REQUEST);

const result = await runProdCli(
'spend-request',
'create',
'--payment-method-id',
'pd_prod_test',
'--merchant-name',
'Test Merchant',
'--merchant-url',
'https://example.com',
'--context',
VALID_CONTEXT,
'--amount',
'5000',
'--expires-at',
'1720100000',
'--no-request-approval',
'--json',
);

expect(result.exitCode).toBe(0);
const sentBody = JSON.parse(lastRequest.body);
expect(sentBody.expires_at).toBe(1720100000);
});

it('does not include expires_at in POST body when --expires-at is omitted', async () => {
setNextResponse(200, BASE_REQUEST);

const result = await runProdCli(
'spend-request',
'create',
'--payment-method-id',
'pd_prod_test',
'--merchant-name',
'Test Merchant',
'--merchant-url',
'https://example.com',
'--context',
VALID_CONTEXT,
'--amount',
'5000',
'--no-request-approval',
'--json',
);

expect(result.exitCode).toBe(0);
const sentBody = JSON.parse(lastRequest.body);
expect(sentBody.expires_at).toBeUndefined();
});

it('sends test flag in POST body when --test is used', async () => {
setNextResponse(200, BASE_REQUEST);

Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/commands/spend-request/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ export function createSpendRequestCli(
approve: opts.approve ? true : undefined,
approval_details: approvalDetails,
metadata,
expires_at: opts.expiresAt,
};

const outputFile = opts.outputFile;
Expand Down
5 changes: 5 additions & 0 deletions packages/cli/src/commands/spend-request/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ export const createOptions = z.object({
.describe(
'Metadata key:value pair (repeatable). Attaches arbitrary string data to the spend request. Max 50 keys, key <= 40 chars, value <= 500 chars. Example: "order_id:ord_123"',
),
expiresAt: z.coerce
.number()
.int()
.optional()
.describe('Unix timestamp (seconds).'),
});

export const listOptions = z.object({
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/resources/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export interface CreateSpendRequestParams {
approve?: boolean;
approval_details?: ApprovalDetail;
metadata?: Record<string, string>;
expires_at?: number;
}

export interface UpdateSpendRequestParams {
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ export interface SpendRequest {
link_transaction_id?: string;
activity_url?: string;
metadata?: Record<string, string>;
expires_at?: number;
created_at: string;
updated_at: string;
}
Expand Down
Loading