split-expense-ynab-venmo-shared
Version:
Shared library code the app Expo+Firebase app 'Split Expense: YNAB + Venmo'
64 lines (52 loc) • 1.68 kB
text/typescript
import { z } from 'zod';
import { objectKeys } from 'ts-extras';
export class VenmoClient {
#accessToken: string;
#defaultChargeeUserId: string;
constructor(config: VenmoConfig) {
this.#accessToken = config.accessToken;
this.#defaultChargeeUserId = config.defaultChargeeId;
}
async requestPayment(details: PaymentDetails) {
try {
const chargeResponse = await fetch('https://api.venmo.com/v1/payments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.#accessToken}`,
},
body: JSON.stringify({
note: details.note,
metadata: {
quasi_cash_disclaimer_viewed: false,
},
amount: details.cents * -0.01,
user_id: this.#defaultChargeeUserId,
audience: 'private',
}),
});
if (!chargeResponse.ok) {
throw new Error(`Venmo charge failed with status ${chargeResponse.status}`);
}
} catch (e) {
console.error('Venmo charge error: ', e);
throw e;
}
}
}
const ChargeeIdSchema = z.string();
export const VenmoEnvVarsSchema = z.object({
DEFAULT_VENMO_CHARGEE_ID: ChargeeIdSchema,
VENMO_API_ACCESS_TOKEN: z.string(),
});
export const VENMO_ENV_VAR_NAMES = objectKeys(VenmoEnvVarsSchema.keyof().Values);
export const VenmoConfigSchema = z.object({
accessToken: z.string(),
defaultChargeeId: ChargeeIdSchema,
});
type VenmoConfig = z.infer<typeof VenmoConfigSchema>;
export const PaymentDetailsSchema = z.object({
cents: z.number(),
note: z.string(),
});
export type PaymentDetails = z.infer<typeof PaymentDetailsSchema>;