Skip to content

Conversation

@wobsoriano
Copy link

@wobsoriano wobsoriano commented Dec 15, 2025

What kind of change does this PR introduce?

Hi everyone, Rob from Clerk here. First of all, thanks for putting up a Wasm Wrapper for Clerk! We added billing recently and figured we can add this endpoints to the FDW as well.

This PR adds support for Clerk's billing API endpoints to the Clerk FDW.

What is the current behavior?

The Clerk FDW currently supports users, organizations, and other core Clerk resources, but does not include any billing-related endpoints. Users cannot query billing plans, subscriptions, statements, or payment data through the FDW.

What is the new behavior?

The Clerk FDW now supports 7 billing-related endpoints:

Table Name Object Requires WHERE
billing_plans billing/plans No
billing_subscription_items billing/subscription_items No
billing_statements billing/statements No
billing_statement billing/statement statement_id
billing_payment_attempts billing/payment_attempts statement_id
user_billing_subscriptions users/billing/subscription user_id
organization_billing_subscriptions organizations/billing/subscription organization_id

Example queries:

-- List all billing plans
SELECT * FROM clerk.billing_plans;

-- Get user's billing subscription
SELECT * FROM clerk.user_billing_subscriptions WHERE user_id = 'user_xxx';

-- Get payment attempts for a statement
SELECT * FROM clerk.billing_payment_attempts WHERE statement_id = 'stmt_xxx';

Additional context

  • Follows existing Orb FDW patterns for parameterized endpoints and error handling
  • Documentation updated with new entity sections and examples

Add support for Clerk billing API endpoints following the Orb FDW pattern:
- billing/plans
- billing/subscription_items
- billing/statements
- users/billing/subscription (requires user_id WHERE clause)
- organizations/billing/subscription (requires organization_id WHERE clause)
- billing/statements/payment_attempts (requires statement_id WHERE clause)

Implements parameterized URL handling using Context and quals extraction,
matching the pattern used in Orb FDW for endpoints like credits/ledger.
@wobsoriano wobsoriano marked this pull request as ready for review December 15, 2025 01:24
Copilot AI review requested due to automatic review settings December 15, 2025 01:24
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support for Clerk's billing API endpoints to the Clerk Foreign Data Wrapper (FDW), enabling users to query billing-related data such as plans, subscriptions, statements, and payment attempts through SQL queries.

Key Changes:

  • Adds 7 new billing-related foreign tables with support for both list and parameterized endpoints
  • Implements parameterized endpoint handling for endpoints requiring user_id, organization_id, or statement_id in the WHERE clause
  • Updates pagination logic to handle endpoints that don't support ordering and single-object responses

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
wasm-wrappers/fdw/clerk_fdw/src/lib.rs Implements billing endpoint support with parameterized URL construction, conditional pagination, and special handling for billing endpoints that don't support order_by
docs/catalog/clerk.md Adds comprehensive documentation for all 7 new billing entities with usage examples and API reference links

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +128 to +143
// Standard endpoints with pagination
// Billing endpoints don't support order_by
let is_billing = self.object.starts_with("billing/");
let qs = if is_billing {
vec![
format!("offset={}", self.src_offset),
format!("limit={BATCH_SIZE}"),
]
} else {
vec![
"order_by=-created_at".to_string(),
format!("offset={}", self.src_offset),
format!("limit={BATCH_SIZE}"),
]
};
let mut url = format!("{}/{}?{}", self.base_url, self.object, qs.join("&"));
Copy link

Copilot AI Dec 15, 2025

Choose a reason for hiding this comment

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

The query string with offset/limit parameters is built for all endpoints (lines 131-142) and used to construct the URL (line 143), but for parameterized endpoints (users/billing/subscription, organizations/billing/subscription, billing/statement, billing/payment_attempts), the URL is completely replaced (lines 153, 167, 181, 195), discarding these parameters. Consider checking if the endpoint is parameterized before building the query string to avoid unnecessary string allocation and formatting.

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

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

low prio

@burmecia
Copy link
Member

Thanks for the PR! Could you format the code to fix the CI failure?

@wobsoriano
Copy link
Author

Thanks for the PR! Could you format the code to fix the CI failure?

Done!

@burmecia
Copy link
Member

For non-existing object, is it possible to return an empty dataset rather than return an error? For example,

select * from clerk.billing_statement where id='123';

This will return an guest fdw error (essentially a HTTP 404 error):

ERROR:  guest fdw error: HTTP status error (404 Not Found) for url (https://api.clerk.com/v1/billing/statements/123): {"errors":[{"message":"not found","long_message":"Resource not found","code":"resource_not_found"}],"clerk_trace_id":"3f10093a7f47b5886c95fce151a81ccd"}

I think an empty result might be more semantically correct, as non-existing isn't really an error.

@wobsoriano
Copy link
Author

@burmecia agree to that, updated!

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.

2 participants