Server-integrations (advanced)
Inspect stored activity, read assigned event contacts, or reconcile an externally completed purchase with Wallkit. Start with the task: the server reference section includes both a guest operation and service-account operations with separate permissions.
1. Choose the actor and supplied credentials
| Job | Existing context / transport | What it establishes |
|---|---|---|
| Inspect user activity | Guest with resource public key in resource header; JSON email | Three stored-record indicators for the email/resource, not authentication or current login. |
| Read event attendees | Authorized resource service-api-key plus resource headers | Assigned user contact rows for an active event in this resource; not pass owners, attendance or current pass validity. |
| External purchase lookup, transaction lookup, recording, update, downgrade or refund recording | Authorized resource service-api-key plus resource; active attached account user | Catalog or local account records, with operation-specific effects; no provider payment/refund request. |
Use keys already supplied to the trusted integration. Keep service credentials out of browser code. A service account must be active, not suspended and attached to an active service-account user. Its resolved role must permit the route, and its account must have full_access or a grant for that exact action. A member token is not a substitute. Root access is a separate ACL bypass, not the example credential.
External purchase controllers also require active user/resource context and reject an attached resource relationship that is locked or suspended. Target-user mutations require the target user to exist and have this resource relationship; they do not separately validate target activation/lock/suspension. Attendee access does not require that the actor own or be assigned a pass.
Service-account initialization can create/update a session, increment counters, extend expiry and record requests/responses even on GET. Invalid service keys can fall back to ordinary context resolution, so do not expect one dedicated invalid-key error. Follow credential transport and each operation’s recovery table.
2. Keep identifiers separate
| Value | Meaning / where used |
|---|---|
| resource public key | Selects the resource and scoped service account; neither a resource secret nor a user ID. |
| Activity lookup first finds a global user after normalization, then requires their relationship with the resource. | |
| user_id | Target Wallkit user for purchase recording/adjustment; transaction lookup has no target-user filter. |
| external_source_id for Pricing lookup | One complete token from a Pricing’s comma-separated external_source_ids; trimmed/case-insensitive. |
| subscription.id / downgrade path subscription_id | Wallkit Pricing ID. A Plan has many Pricings; this ID is not the user’s membership relationship. |
| membership relationship ID | Existing user/Plan/Pricing record. A linked purchase can reference it, but downgrade selects a first external relationship by user/Pricing. |
| transaction.id in request body | External transaction identifier supplied by the external system; exact resource-scoped match for lookup. |
| transaction.id in lookup result | Local Wallkit transaction ID. The external identifier is not echoed by the base result. |
| refund external_subscription_source_id | Optional catalog mapping token that can trigger membership downgrade; not a provider membership ID. |
| event / ticket / pass ID | Event contains tickets; assigned passes select attendee users. Attendee result returns ticket ID, not pass ID. |
Reader question: what does each external identifier resolve?
flowchart LR
CatalogToken[External catalog token] -->|resource mapping| Pricing[Wallkit Pricing]
ExternalOrder[External transaction ID] -->|resource lookup| Transaction[Stored transaction]
Transaction -->|returned user_id| Target[Target user]
UserAndPricing[Target user and Pricing] -->|separate recording request| Membership[External membership record]
MemberContext[Established member context] -->|separate content check| Decision[Allow or deny decision]
Use the catalog token to find a Pricing. Use the external transaction ID to find a stored transaction and its user_id. A separate recording request uses a target user and Pricing to create/update an external membership and linked records; the diagram does not promise atomic writes or successful completion. An established member context goes through a separate content check. Payment collection and refund money movement happen in the external system; this diagram contains no automatic payment-to-access chain.
3. Inspect activity or attendees as independent tasks
For activity, send JSON email reader@example.com with resource to POST check-user-activity. A synthetic result can be:
{"has_user_resource_relationship_password":true,"is_sent_reset_password":false,"is_exist_sessions":true}
This means a nonempty resource password field, no matching stored reset-mail row, and session/archive history. It does not verify a password, mail delivery, consent or current session. Three false flags differ from user_not_found or user_not_registered_in_resource errors. The IP/resource/action counter is consumed before email validation, with no helper-defined time window. Continue with a separate identity flow when needed.
For attendees, request event 1001, optionally restricting ticket 2001, with the supplied service headers. See the equivalent requests in event attendees. Rows represent assigned users grouped by user/ticket, not owners or active passes. Default limit is 100, maximum 1000, and offset counts rows. The total counts distinct users, so has_more can understate remaining grouped rows. A caught collection failure can also return an empty list. Use the Event tickets activation and passes for the separate ownership, invitation and access tasks.
4. Reconcile an external purchase before recording
All excerpts below are synthetic and unexecuted. Full equivalent cURL, Node.js .mjs fetch and Python urllib requests are linked in the operation examples. WALLKIT_API_BASE is the supplied scheme/host only; each path includes /api/v1.
-
Resolve the catalog choice. Look up catalog-reader-monthly with the existing service context. The result’s subscription.id 3001 is a Wallkit Pricing ID, with Plan ID 4001. The lookup can return inactive/private Pricings and does not grant membership. If the same complete token maps to more than one Pricing, no stable selection order is defined. Ask the integration owner to resolve that ambiguity before recording.
{"subscription":{"id":3001,"plan_id":4001,"external_source_ids":"catalog-reader-monthly","next_subscription":null,"downgrade_subscription":null}} -
Inspect existing transaction recording. Look up order-reader-1001. The excerpt below is the existing-record branch: compare user_id with intended user 1001. If it matches, inspect existing memberships and resolve any discrepancy; skip another creation request for this external ID. If it names a different user, stop and reconcile the mismatch with the integration owner. This lookup is resource-scoped, not user-filtered. Its local id 5001 differs from the external ID; succeeded is a recorded status, not fresh provider confirmation.
{"transaction":{"id":5001,"user_id":1001,"status":"succeeded","amount":1000,"currency":"USD","amount_refunded":0}}The separate absent-record branch begins only if the lookup returns HTTP 404 get_transaction_error with Transaction not found, the external purchase was completed separately, and uncertain prior attempts have been reconciled with the integration owner. Only that branch proceeds to step 3. Absence does not make the POST idempotent: duplicate external IDs are not rejected, and lookup/write is not an atomic reservation.
-
Record the purchase in the separate absent-record branch. This example assumes no transaction has been recorded for order-reader-1001, the external purchase is separately completed, and prior uncertain attempts are resolved; it does not follow the existing-record result shown in step 2. Use target user 1001 with existing resource relationship and Pricing 3001. POST external subscriptions supplies these objects:
{"subscription":{"id":3001,"end_date":"2026-11-01","is_trial":false},"transaction":{"id":"order-reader-1001","is_live_mode":false,"amount":1000,"currency":"USD","data":"External purchase recorded by the integration"}}Amount 1000 is an illustrative stored value, not a currency-scale claim. Intended HTTP 201 returns success:true only. An existing external user/Pricing membership receives the new end date/trial flag and keeps autorenew; otherwise the membership helper can replace memberships/history, enforce once/trial rules, set external autorenew true and apply single_subscription/sponsorship/content-view effects. A first higher-priced resource membership can block the selection. Read creation effects and recovery before adapting this request.
If amount is absent from a valid transaction object, both amount and currency come from Pricing, overriding a supplied currency. Missing/null/malformed objects can fail after membership work with no dependable error envelope. Some saves are not checked, database transactions can be nested, and event attempts can happen before or after commit. The request can therefore leave some changes in place when it fails. Do not blindly repeat an uncertain POST.
-
Inspect local state and decide access separately. Read existing memberships, inspect recorded transaction, and use an established member context for content access. The acknowledgement returns no IDs. It confirms neither provider payment nor permission to serve an article.
5. Choose the right later adjustment
| Need | Operation / input difference | Consequential limit |
|---|---|---|
| Change local trial/renewal/end-date fields | Update existing external membership; subscription_end_date, not create’s end_date | Boolean changes strictly compare filtered input then invert stored flags. Date is string-filtered, not create-style date-validated; no provider renewal change or replay guarantee. |
| Apply configured membership transition | Downgrade by Pricing ID | Pricing downgrade then resource downgrade_subscription_id fallback, otherwise history/delete. Inner failures may be swallowed; success:true does not certify removal or replacement. No provider refund. |
| Record money already refunded externally | Record external refund | Matching external transaction must belong to target user/resource. amount_refunded is overwritten; 0 means full amount. Partial recording can trigger the same entire membership downgrade. No provider money transfer. |
For a partial externally completed refund, send:
{"transaction":{"id":"order-reader-1001","refund_amount":500}}
The intended HTTP 200 success:true reports no amount or resulting membership. Qualifying linked purchase relationships can trigger external user/Pricing downgrade; optional external_subscription_source_id can select a mapped Pricing as another downgrade target. Missing/inapplicable relationships can skip, but invalid mapping or later failures can produce an error after transaction work. No deduplication, amount cap, cumulative-delta calculation, atomicity or safe replay is promised. Inspect the stored refund amount and resulting memberships, and reconcile actual money with the external system.
What follows
Use the exact operation’s recovery table to distinguish resource/user/grant errors from an uncertain write or an ordinary empty result. Ask the integration owner to resolve mismatched IDs, duplicate mappings or partial records before another mutation. Continue through a separate content-access decision when the application needs to serve protected content.