Como resolvemos o problema de moeda de mercado do Recharge com AWS Lambda

Background
O Recharge não recalcula automaticamente a presentment_currency nem o preço associado quando uma assinatura é atualizada — troca de variante, nova assinatura, qualquer alteração. Para clientes fora do mercado base em USD, isso significa preço e moeda errados armazenados indefinidamente.
A solução foi uma etapa pós-atualização dentro do nosso serviço em AWS Lambda: ela detecta mercados fora do USD e corrige o preço programaticamente, buscando o valor contextual correto direto no Shopify.
01Visão geral da arquitetura
O serviço é uma função AWS Lambda publicada com Serverless Framework v3, rodando em Node.js 20.x / ARM64 dentro de uma VPC privada (usrv-subscriptions). Expõe um único endpoint HTTP via API Gateway:
POST /{stage}/subscriptions/update
Toda configuração sensível — tokens de API, valor do mercado comparador, URLs da Shopify — fica no AWS SSM Parameter Store e é injetada como variável de ambiente da Lambda no momento do deploy.
MARKET_TO_COMPARE: ${ssm:/${self:provider.stage}/GLOBAL/MARKET_TO_COMPARE}
Esse valor é tipicamente USD — o mercado base que o Recharge assume por padrão.
02Request Flow
Handler e middleware
As requisições chegam em src/handler/subscriptionsUpdate.ts e passam por um pipeline de middlewares Middy:
O handler instancia três clientes de serviço — RechargeService, ShopifyGateway e DynamoService — e delega a execução para SubscriptionService.subscriptionsUpdate.
Operações em lote no Recharge
Três operações em lote são executadas sequencialmente contra a REST API do Recharge (https://api.rechargeapps.com):
Todas usam uma instância compartilhada do Axios com retry: 3 tentativas, backoff de 1s / 2s / 3s, disparando em erros 5xx e falhas de rede. Ao final, os resultados são persistidos em DynamoDB (usrv-subscriptions-{stage}) com ID da assinatura, timestamp e ação (created, updated, deleted) como log de auditoria.
Detecção da moeda de mercado
Aqui está o núcleo da correção. Assim que as operações em lote terminam:
const isMarketPriceUpdateRequired =
await this.isSubscriptionRequiredToUpdateMarketPrice(baseSubId);
private async isSubscriptionRequiredToUpdateMarketPrice(baseSubId: string) {
const market = await this.rechargeService.getMarket(baseSubId);
const marketToCompare = `${process.env.MARKET_TO_COMPARE}`;
return market !== marketToCompare;
}
O fluxo é direto: chama GET /subscriptions/{id}, lê o campo presentment_currency e compara com MARKET_TO_COMPARE. Se forem diferentes, dispara a correção de preço.
Resolução do country code
O país do cliente é resolvido em duas chamadas: GET /subscriptions/{id} extrai o address_id e GET /addresses/{addressId} devolve o country_code — CA, GB, AU, e assim por diante.
Buscando o preço de mercado no Shopify
Para cada assinatura criada ou atualizada, o serviço consulta o Shopify Admin GraphQL usando contextualPricing — o preço calculado pela própria Shopify para aquele mercado:
query getProductVariant($id: ID!, $country: CountryCode!) {
productVariant(id: $id) {
id
contextualPricing(context: { country: $country }) {
price {
amount
currencyCode
}
}
}
}
# variables
# id: gid://shopify/ProductVariant/{shopify_variant_id}
# country: {country_code}
Correção do preço no Recharge
Com o preço correto em mãos, um único PUT resolve:
O fluxo ponta a ponta
Client → POST /v1/subscriptions/update
(subsToCreate, subsToCancel, subsToUpdate)
│
▼
AWS Lambda (Handler + Middy)
│
▼
SubscriptionService
├─ Recharge: createSubscriptions (lote)
├─ Recharge: cancelSubscriptions (lote)
├─ Recharge: updateSubscriptions (lote)
├─ DynamoDB: batchInsert (auditoria)
│
├─ Recharge GET /subscriptions/{id}
│ └─ lê presentment_currency
│ │
│ ▼ (se moeda ≠ MARKET_TO_COMPARE)
├─ Recharge GET /subscriptions/{id} → address_id
│ └─ Recharge GET /addresses/{id} → country_code
│
└─ para cada assinatura criada/atualizada:
├─ Shopify Admin GraphQL: contextualPricing(country)
│ └─ retorna { amount, currencyCode }
└─ Recharge PUT /subscriptions/{id}
└─ { price, presentment_currency }
03Decisões de projeto
Conclusão
Operações de assinatura multi-mercado expõem lacunas que nenhuma plataforma resolve sozinha. O Recharge cobre o ciclo de vida da recorrência; a Shopify cobre a precificação por mercado. Costurar as duas de forma confiável é trabalho de engenharia.
A lição prática: trate a correção de moeda como uma etapa explícita e idempotente do fluxo, não como efeito colateral. Com detecção condicional, retries e log de auditoria em DynamoDB, o custo operacional é próximo de zero e o cliente nunca mais vê o preço errado.
Auditamos o fluxo de assinaturas, mapeamos onde preço e moeda divergem e implementamos a correção.
Falar com a engenharia ↗