* Create the webhook integration in RevenueCat via the REST API v2. * * Sim generates the Authorization header secret, registers the integration * with that secret, and stores both the returned integration id (`externalId`) * and the secret (`authHeaderSecret`) so verifyAuth can
(ctx: SubscriptionContext)
| 72 | * @see https://www.revenuecat.com/docs/api-v2 (Integration > Create a webhook integration) |
| 73 | */ |
| 74 | async createSubscription(ctx: SubscriptionContext): Promise<SubscriptionResult | undefined> { |
| 75 | const config = getProviderConfig(ctx.webhook) |
| 76 | const { apiKey, projectId, triggerId, environment } = config as { |
| 77 | apiKey?: string |
| 78 | projectId?: string |
| 79 | triggerId?: string |
| 80 | environment?: string |
| 81 | } |
| 82 | |
| 83 | if (!apiKey) { |
| 84 | throw new Error( |
| 85 | 'RevenueCat Secret API key is required to create the webhook. Provide a v2 Secret API key with the project_configuration:integrations:read_write permission.' |
| 86 | ) |
| 87 | } |
| 88 | |
| 89 | if (!projectId) { |
| 90 | throw new Error('RevenueCat Project ID is required to create the webhook.') |
| 91 | } |
| 92 | |
| 93 | const { REVENUECAT_TRIGGER_TO_API_EVENT_TYPE } = await import('@/triggers/revenuecat/utils') |
| 94 | const eventType = triggerId ? REVENUECAT_TRIGGER_TO_API_EVENT_TYPE[triggerId] : undefined |
| 95 | |
| 96 | const authHeaderSecret = generateId() |
| 97 | const requestBody: Record<string, unknown> = { |
| 98 | name: `Sim webhook (${triggerId ?? 'revenuecat'})`, |
| 99 | url: getNotificationUrl(ctx.webhook), |
| 100 | authorization_header: authHeaderSecret, |
| 101 | } |
| 102 | if (eventType) { |
| 103 | requestBody.event_types = [eventType] |
| 104 | } |
| 105 | if (environment === 'production' || environment === 'sandbox') { |
| 106 | requestBody.environment = environment |
| 107 | } |
| 108 | |
| 109 | const response = await fetch( |
| 110 | `${REVENUECAT_API_BASE}/projects/${encodeURIComponent(projectId)}/integrations/webhooks`, |
| 111 | { |
| 112 | method: 'POST', |
| 113 | headers: { |
| 114 | Authorization: `Bearer ${apiKey}`, |
| 115 | 'Content-Type': 'application/json', |
| 116 | }, |
| 117 | body: JSON.stringify(requestBody), |
| 118 | } |
| 119 | ) |
| 120 | |
| 121 | if (!response.ok) { |
| 122 | const errorBody = (await response.json().catch(() => ({}))) as Record<string, unknown> |
| 123 | logger.error( |
| 124 | `[${ctx.requestId}] Failed to create RevenueCat webhook for webhook ${ctx.webhook.id}. Status: ${response.status}`, |
| 125 | { response: errorBody } |
| 126 | ) |
| 127 | |
| 128 | let message = 'Failed to create webhook integration in RevenueCat' |
| 129 | if (response.status === 401) { |
| 130 | message = 'RevenueCat authentication failed. Verify your v2 Secret API key is correct.' |
| 131 | } else if (response.status === 403) { |
nothing calls this directly
no test coverage detected