{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["admonition"]},"type":"markdown"},"seo":{"title":"Integration Patterns","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"integration-patterns","__idx":0},"children":["Integration Patterns"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Before writing any code, decide which integration pattern fits your use case. The right pattern determines which API approach, authentication flow, and sync strategy to use."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"choosing-a-pattern","__idx":1},"children":["Choosing a pattern"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Use case"},"children":["Use case"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Recommended approach"},"children":["Recommended approach"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Validate or retrieve one record while a user is waiting"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Direct app-specific API endpoint"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Pull all records for a dataset, such as event registrations"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Saved query or Query API"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Pull records modified since the last sync"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Query API with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sys_last_modified_at"]}," criteria"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Populate a mobile app, vendor database, or external cache"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Scheduled Query API syncs"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Pull data across multiple Rhythm apps or modules"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Query API"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Let customer admins adjust fields or filters without code changes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Saved Rhythm query"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Browser login, WordPress login, or SSO"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Applicable ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/sso"},"children":["SSO guide"]}]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"info","name":"General rule"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use direct app endpoints for real-time, record-specific workflows. Use the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/query"},"children":["Query API"]}," for scheduled syncs, reporting-style extracts, cross-app datasets, and incremental jobs."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"choosing-an-oauth-flow","__idx":2},"children":["Choosing an OAuth flow"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Integration scenario"},"children":["Integration scenario"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Recommended flow"},"children":["Recommended flow"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Scheduled script, backend sync, batch job, or server-to-server process with no user present"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/tutorials/authentication#client-credentials-flow"},"children":["Client Credentials / M2M"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Server-rendered website where a real user logs in"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/tutorials/authentication#authorization-code-flow"},"children":["Authorization Code"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Mobile app or single-page application where a real user logs in"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/tutorials/authentication#authorization-code-with-pkce"},"children":["Authorization Code with PKCE"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Browser login, SSO, WordPress, or redirect issues"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Applicable ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/sso"},"children":["SSO guide"]}]}]}]}]}]},{"$$mdtype":"Tag","name":"Admonition","attributes":{"type":"warning","name":"M2M is not for users"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If a real user is involved, do not use Machine-to-Machine authentication. M2M tokens are not user-specific and count against the customer's monthly token limit. See the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/tutorials/authentication#client-credentials-flow"},"children":["authentication guide"]}," for caching requirements."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"incremental-sync-using-sys_last_modified_at","__idx":3},"children":["Incremental sync using \"sys_last_modified_at\""]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For integrations that only need changed records, filter your query on the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sys_last_modified_at"]}," field using a rolling lookback window rather than an exact timestamp. A rolling window protects against missed runs, time zone edge cases, and replication lag."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Recommended pattern:"]}]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Build or save a query in Rhythm"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Filter to the specific business context (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["event_id"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["context_id"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Include ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["sys_last_modified_at"]}," as an output field"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Set criteria to records modified within the last 24–48 hours"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Run the query on a schedule"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Upsert records in the external system using the Rhythm record ID"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["De-duplicate records that appear in overlapping sync windows"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Handling status changes"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Do not filter out cancelled or inactive records in incremental syncs unless the downstream system has another way to deactivate them. Include status changes so the external system can update or remove records accordingly."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["ID correlation"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Rhythm uses different IDs for different purposes — do not assume one ID serves every need. For event registration integrations, store all three:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"ID"},"children":["ID"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Represents"},"children":["Represents"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["contact_id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The person / contact record"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The specific registration record"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["event_id"]}," / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["context_id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The event or program that this record exists under"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A single contact may have multiple registrations (for example, if they cancel and repurchase), so storing only the contact ID is not sufficient to identify a specific registration."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"static-query-vs-saved-query","__idx":4},"children":["Static query vs saved query"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":""},"children":[]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Static query"},"children":["Static query"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Saved query"},"children":["Saved query"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Query definition lives in"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your code"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Rhythm (referenced by ID)"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Use when"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Field list should be version-controlled; filters should not change without a release"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Customer admins may need to adjust fields; Support needs to help refine filters"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["See the ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/guides/query"},"children":["Query Guide"]}," for how to build and execute both types."]}]},"headings":[{"value":"Integration Patterns","id":"integration-patterns","depth":1},{"value":"Choosing a pattern","id":"choosing-a-pattern","depth":2},{"value":"Choosing an OAuth flow","id":"choosing-an-oauth-flow","depth":2},{"value":"Incremental sync using \"sys_last_modified_at\"","id":"incremental-sync-using-sys_last_modified_at","depth":2},{"value":"Static query vs saved query","id":"static-query-vs-saved-query","depth":2}],"frontmatter":{"seo":{"title":"Integration Patterns"}},"lastModified":"2026-05-18T16:17:22.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/integration-patterns","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}