- Frictionless merchant onboarding — one-click connect from either dashboard
- No API paywall — merchants don’t need a paid API plan to use your integration
- Scoped tokens — each merchant gets an isolated API key; revocable at any time
- Automatic cleanup — when a merchant disconnects or uninstalls, access is revoked instantly
How it works
The Partner Integration Framework uses a secure handshake protocol. Either side — your app or Appstle — can initiate the connection. Both flows end with your app receiving a scoped API token.Getting started
Step 1: Get onboarded
To get started, reach out to the Appstle team at support@appstle.com with the information below. Our team will set up your partner account and send you your credentials.What you’ll need to provide
API namespaces — what you call vs. what is internal
Three URL namespaces appear in this codebase. As a third-party partner, you only ever call the first one. The others exist for Appstle’s merchant portal and inter-app integrations and are documented here so the surface area is unambiguous:/api/integrations/..., it’s an internal Appstle flow and doesn’t apply to your integration.
What you’ll receive
Once onboarded, you’ll receive three values:Step 1b: Choose your authentication mode
Appstle supports two ways to authenticate partner API calls. Your auth mode is configured during onboarding.Option A: Partner Secret (default)
The simplest approach. Pass your secret in a header with every request:Option B: HMAC-SHA256
A more secure approach where requests are signed with a shared HMAC key. Instead of sending the secret directly, you compute a signature over the request body. Headers required:- Get the current Unix timestamp (seconds, not milliseconds)
- Concatenate the timestamp and the raw JSON request body:
timestamp + body - Compute HMAC-SHA256 of that string using your HMAC key
- Send the hex-encoded result in
X-Partner-Signature
- Partner Secret — simpler to implement, fine for most integrations
- HMAC-SHA256 — better security (secret never sent over the wire), recommended for high-volume or security-sensitive integrations
Step 1c: Choose your connect mode
Appstle supports two ways to establish merchant connections. Your connect mode is configured during onboarding.Option A: Nonce Handshake (default)
The full two-way verification flow described in this guide. Both sides verify each other using a one-time nonce. After the handshake, your app receives an Appstle API key (apst_...) to call Appstle’s External API.
Best for: partners who want to read/write data in Appstle (customer points, transactions, rewards, etc.)
Option B: Simple Token Exchange
A streamlined flow where your app sends its own access token to Appstle (or Appstle calls your connect endpoint and you return one). No nonce, no verify endpoint needed. Appstle stores your token and uses it to call your API when needed. Best for: partners where Appstle needs to call the partner’s API (e.g., syncing data to the partner’s platform), rather than the partner calling Appstle’s API. Key difference from Nonce Handshake: in Simple Token Exchange, your app provides its own access token to Appstle. Appstle stores this token and uses it to push data to your API (via yoursync_path — see Data Sync below). Your app does not receive an Appstle API key in this mode.
sync_path during onboarding. Contact support@appstle.com to discuss your use case.access_token is stored securely but will not be activated until the merchant approves the connection from their Appstle dashboard. Once approved, Appstle calls your /appstle/approved endpoint to confirm (see Handling the approval callback)./appstle/connect endpoint with { "shop_domain": "..." }. Your app responds with:
Step 2: Understand the callback nonce
What is a callback nonce?
A nonce (number used once) is a random, single-use string that proves both sides of the connection are who they claim to be. It prevents replay attacks and ensures the handshake can’t be forged.Requirements
How to generate a nonce
Use your language’s cryptographically secure random number generator.How to store a nonce
Store the nonce temporarily, keyed by shop domain, with a 5-minute expiry. Delete it after verification.Step 3: Implement your endpoints
Your app must expose two HTTP endpoints that Appstle calls during the connection handshake. The paths default to/appstle/connect and /appstle/verify but can be customized during onboarding.
Both endpoints must:
- Accept
POSTrequests with a JSON body - Return JSON responses
- Be accessible over HTTPS (Appstle will not call HTTP endpoints)
- Respond within 10 seconds (or the request will time out)
- Be idempotent. Appstle may retry a callback on transient failure, and a merchant flipping connect/disconnect repeatedly will exercise the same endpoint with the same
(shop_domain, partnerId)pair. Treat every call as an upsert keyed by(shop_domain, partnerId)— never blindly insert. The same rule applies to your/appstle/approvedand/appstle/disconnectendpoints described later.
Endpoint 1: POST /appstle/connect
When is this called? Appstle calls this when a merchant initiates the connection from Appstle’s dashboard (Flow B).
What does it receive?
- Validate the shop — check that this
shop_domainexists in your system. If you don’t recognize the shop, return an error. - Store the nonce and callback URL — save
callback_nonceandcallback_urlassociated with thisshop_domain. You’ll need them to complete the handshake. - Call back to Appstle — either immediately (auto-approve) or after merchant confirmation, call the
callback_urlto complete the connection. See Completing the handshake below. - Return a success response — any
2xxstatus code tells Appstle the request was received.
Endpoint 2: POST /appstle/verify
When is this called? Appstle calls this when a merchant initiates the connection from your app’s dashboard (Flow A). Appstle is asking your app: “Did you actually send this nonce?”
What does it receive?
- Look up the stored nonce for this
shop_domain - Compare the
callback_noncefrom the request against your stored nonce - If they match: delete the stored nonce (it’s single-use) and return
{ "verified": true } - If they don’t match: return
{ "verified": false }
Step 4: Implement the connect flow (your dashboard)
Now build the merchant-facing “Connect Appstle Loyalty” button in your app’s dashboard.Partner-initiated connect (Flow A) — step by step
This is the flow where the merchant clicks “Connect Appstle” in your dashboard.Merchant clicks "Connect Appstle" in your dashboard
Your app generates a cryptographically random nonce
shop_domain with a 5-minute TTL.Your app calls POST /api/partner/{id}/connect
shop_domain, the callback_nonce, and your Partner Secret.Appstle validates your Partner Secret
Appstle calls YOUR /appstle/verify endpoint
shop_domain and the same callback_nonce.Your /appstle/verify checks the nonce
{ "verified": true }.Appstle returns pending_merchant_approval
Merchant approves in their Appstle dashboard
Appstle creates a scoped API key
/appstle/approved endpoint.Your app stores the access_token
/appstle/approved endpoint (see Handling the approval callback below). Pending requests expire after 30 days if not acted on.Appstle-initiated connect (Flow B) — step by step
This is the flow where the merchant clicks “Connect” in Appstle’s dashboard.Merchant clicks "Connect {YourApp}" in Appstle's dashboard
Appstle calls POST /api/partner/{id}/initiate-connect
Appstle generates a nonce (5-min TTL) and calls YOUR /appstle/connect
shop_domain, app, callback_url, and callback_nonce.Your /appstle/connect stores the nonce and callback_url
shop_domain for the verify step.Your app calls the callback_url (Appstle's /verify endpoint)
shop_domain, callback_nonce, and your Partner Secret.Appstle verifies the nonce and issues a scoped API key
access_token is returned in the response body.Your app stores the access_token
Completing the handshake (Flow B)
After your/appstle/connect endpoint receives the nonce and callback URL, your app completes the connection by calling Appstle’s verify endpoint:
Using the API token
After a successful connection, your app has anaccess_token (prefixed with apst_). For Appstle-initiated connections (Flow B), the token is returned immediately in the verify response. For partner-initiated connections (Flow A), the token is delivered asynchronously to your /appstle/approved endpoint after the merchant approves (see Handling the approval callback below).
Use this token exactly like a merchant API key — pass it in the X-API-Key header:
Token properties
Available endpoints
Partner tokens grant access to the same External API endpoints as merchant API keys:- Customer loyalty data —
GET /api/external/customer-loyalty - Point transactions —
GET /api/external/point-transaction-history/{customerId} - Add points —
POST /api/external/add-points(requires READ_WRITE) - Redeem points —
POST /api/external/redeem-points(requires READ_WRITE) - Add store credits —
POST /api/external/add-credits(requires READ_WRITE) - Enroll customer —
POST /api/external/enroll-customer(requires READ_WRITE) - And all other
/api/external/*endpoints
Data sync (push model)
Some integrations work best when Appstle pushes data to your app, rather than your app pulling from Appstle’s API. For example, a search platform might need Appstle to push customer loyalty data so it can be indexed alongside other store data.How it works
During onboarding, you can configure async_path on your server (e.g., /appstle/sync). When loyalty events occur (points earned, tier changes, etc.), Appstle calls your endpoint with the relevant data.
Authentication
When Appstle calls your endpoints, it authenticates using the auth mode configured for your partner:- Partner Secret mode: no additional headers (your endpoints are responsible for validating the source — consider IP allowlisting)
- HMAC-SHA256 mode (recommended): Appstle signs every request with
X-Partner-TimestampandX-Partner-Signatureheaders. Your app should verify the HMAC signature to confirm the request came from Appstle.
Pull vs push — which model do I need?
Disconnecting
Merchant disconnects from Appstle
Merchants can disconnect your integration anytime from Appstle Dashboard → Settings → Partner Connections. When they do:- Your API token for that merchant is revoked immediately
- Subsequent API calls will return
401 Unauthorized - Appstle sends a disconnect webhook to your app (if you configured a
disconnect_pathduring onboarding — see below) - Your app should handle this gracefully and show a “Reconnect” option
401 responses and update your UI to show the connection as disconnected:
Disconnect webhook (first-class endpoint)
Configure adisconnect_path during onboarding (defaults to /appstle/disconnect). Appstle calls this whenever a merchant disconnects — from the Appstle dashboard, from your app, or by uninstalling Appstle entirely. You should implement this endpoint for every integration — it is the only reliable signal that the merchant has revoked access on Appstle’s side. Polling 401 responses as a fallback works but lags behind.
Request body from Appstle:
X-Partner-Timestamp, X-Partner-Signature) so you can verify it came from Appstle.
Your endpoint must:
- Look up the connection without filtering on status. Don’t
WHERE status = 'active'— if the merchant rapid-clicks disconnect twice, the second call may arrive when the row is already inactive. Find by(shop_domain, partnerId)only. - Revoke the Appstle access token idempotently. If the token is already revoked or absent, return success — don’t error. Revocation must be safe to call repeatedly.
- Mark the local connection inactive. Clear or null out the stored Appstle token so subsequent API calls don’t try to use it.
- Return
2xxeven when there was nothing to do. A no-op disconnect is a successful disconnect from Appstle’s perspective.
401 responses from the Appstle API as a fallback signal that the connection was revoked.Partner disconnects programmatically
Your app can disconnect a merchant using your partner authentication (Partner Secret or HMAC-SHA256):Check connection status
GET /api/partner/{partnerId}/status?shop_domain=... is the authoritative source of truth for whether a merchant is connected. If your UI shows a “Connected” badge, derive it from this endpoint — not from whether you happen to have a stored API key locally.
Partners can authenticate with their Partner Secret or HMAC signature:
Handling the approval callback
When a merchant approves a partner-initiated connection, Appstle delivers the API token by calling an endpoint on your server. This applies to partner-initiated connections only — Appstle-initiated connections (Flow B) return the token immediately.Endpoint: POST /appstle/approved
The path defaults to /appstle/approved but can be customized during onboarding (configured as approval_callback_path).
Request body from Appstle (Nonce Handshake mode):
2xx status code with a JSON body (e.g., { "success": true }). If your endpoint returns a non-2xx status (e.g., 401 Unauthorized), the connection is still approved on Appstle’s side, but your app won’t know — see What if the callback fails? below.X-Partner-Timestamp, X-Partner-Signature) so you can verify it came from Appstle.
What if the callback fails?
If your endpoint is unreachable or returns an error, the connection is still approved on Appstle’s side. The API token exists and is valid. Your app can:- Poll the status endpoint — check
GET /api/partner/{id}/status?shop_domain=...until the status isactive - Retry from Appstle’s side — currently, Appstle does not automatically retry the callback. Contact support if you need the token re-delivered.
What if the merchant rejects?
If the merchant clicks “Reject,” the connection status changes torejected and Appstle notifies your app via the disconnect webhook (if configured). Your app should handle this gracefully — show the merchant that the connection was not approved.
Error handling
All partner endpoints return structured error responses:Error codes
Idempotency requirements — recap
The integration framework relies on partners treating callbacks as at-least-once. Concretely:- Connect / approval callbacks: upsert by
(shop_domain, partnerId). Two/appstle/approvedcalls for the same shop must produce the same end state, not two rows. - Disconnect callback: find the connection without filtering on status; revoke tokens idempotently; return
2xxeven when there is nothing to do. - Status reads: safe by definition — no side effects.
Security checklist
Before going live, verify all of these:- Partner Secret / HMAC key is stored in environment variables or a secrets manager — not hardcoded in source code
- Nonces are generated using a cryptographically secure random generator (
crypto.randomBytes,secrets.token_hex,SecureRandom, etc.) - Nonces are stored with a TTL (≤ 5 minutes) and deleted after verification
- Nonces are compared using a constant-time comparison to prevent timing attacks (most frameworks do this by default for string equality)
- Endpoints are served over HTTPS — Appstle will not call HTTP endpoints
shop_domainis validated in your/appstle/connectand/appstle/verifyendpoints — reject domains you don’t recognize- Access tokens are stored encrypted at rest (or in a secrets manager)
- 401 responses are handled gracefully — show a “Reconnect” option, don’t break silently
- Error responses from Appstle are logged for debugging
- (HMAC only) Server clock is synced via NTP — timestamps more than 5 minutes off will be rejected
- (If using disconnect webhook) Your
/appstle/disconnectendpoint cleans up stored tokens and marks the connection as inactive
Complete example: partner-initiated flow (Node.js)
Here’s a full, copy-pasteable implementation of Flow A in Express:Complete example: partner-initiated flow (Python)
FAQ
Can a merchant have multiple partner connections?
Can a merchant have multiple partner connections?
What happens if a merchant uninstalls Appstle Loyalty?
What happens if a merchant uninstalls Appstle Loyalty?
Can I change my partner's permission level (READ_ONLY vs READ_WRITE) after onboarding?
Can I change my partner's permission level (READ_ONLY vs READ_WRITE) after onboarding?
What's the rate limit for partner API calls?
What's the rate limit for partner API calls?
429 Too Many Requests, implement exponential backoff.How do I test the integration before going live?
How do I test the integration before going live?
What if the nonce expires before I can complete the handshake?
What if the nonce expires before I can complete the handshake?
Do I need to implement both Flow A and Flow B?
Do I need to implement both Flow A and Flow B?
/appstle/approved endpoint to receive API tokens after merchant approval (Flow A).Can I reconnect a merchant without them doing anything?
Can I reconnect a merchant without them doing anything?
Why does partner-initiated connect require merchant approval?
Why does partner-initiated connect require merchant approval?
How long does a pending approval last?
How long does a pending approval last?
What happens if the merchant rejects the connection?
What happens if the merchant rejects the connection?
rejected and your app is notified via the disconnect webhook (if configured). The merchant can be asked to reconnect later if they change their mind — your app can initiate a new connection request.Need help?
- Partner onboarding & technical support: support@appstle.com
- Integration guide: Third-Party Integration Guide (for direct API key usage)