Skip to main content
Build a seamless, zero-configuration integration between your app and Appstle Subscriptions. Once connected, your app gets a scoped API token for each merchant — no manual key exchange needed.
Why become a Partner?
  • 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.
Merchant approval: When your app initiates a connection (Flow A), the merchant must approve it from their Appstle dashboard before you receive an API token. When the merchant initiates from Appstle’s side (Flow B), the connection is approved instantly because the merchant is the one clicking “Connect.”

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

Not sure about some of these? Only the first four fields are required to get started. You can always reach out to support@appstle.com to change your authentication mode, connect mode, or add a sync path later.
Recommended default for new partners: Simple Token Exchange + Partner Secret. This is the lowest-friction setup — your app generates a single access token per merchant, hands it to Appstle, and authenticates calls with an X-Partner-Secret header. No nonce storage, no HMAC computation, no /appstle/verify endpoint to implement. Pick this unless you specifically need Appstle to call your API on behalf of a merchant (use Nonce Handshake) or your security review mandates request signing (use HMAC-SHA256).

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: If you see an example referring to /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:
Your Partner Secret is shown only once during onboarding. Copy it immediately and store it in a secure location (environment variable, secrets manager, etc.). If you lose it, contact Appstle to rotate it — the old secret will be invalidated immediately.
Store your credentials as environment variables:
.env

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:
That’s it. No computation needed. Good for getting started quickly.

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:
How to compute the signature:
  1. Get the current Unix timestamp (seconds, not milliseconds)
  2. Concatenate the timestamp and the raw JSON request body: timestamp + body
  3. Compute HMAC-SHA256 of that string using your HMAC key
  4. Send the hex-encoded result in X-Partner-Signature
Timestamp validation: Appstle rejects requests where the timestamp is more than 5 minutes from the server’s current time. Make sure your server clock is synced (NTP).
Which should I choose?
  • 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
Both are equally supported. You can switch modes later by contacting Appstle.

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 (subscription contracts, billing attempts, product swaps, 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 your sync_path — see Data sync below). Your app does not receive an Appstle API key in this mode.
Need both directions? If you need to both push data to Appstle AND have Appstle push data to you, use the Nonce Handshake mode and provide a sync_path during onboarding. Contact support@appstle.com to discuss your use case.
How Simple Token Exchange works: Partner-initiated:
Response:
Your 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-initiated: Appstle calls your /appstle/connect endpoint with { "shop_domain": "..." }. Your app responds with:
With Simple Token Exchange, your app does NOT receive an Appstle API key. If you also need to call Appstle’s External API, use the Nonce Handshake mode instead.

Step 2: Understand the callback nonce

This section applies to Nonce Handshake mode only. If you’re using Simple Token Exchange, skip to Step 4.
Before implementing, you need to understand the callback nonce — it’s the core security mechanism of the handshake.

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.
Common mistakes:
  • Math.random().toString(36) — not cryptographically random, predictable
  • uuid.v4() — UUIDs are not designed as security tokens (some implementations use weak RNG)
  • Date.now().toString() — trivially guessable
  • Reusing nonces across multiple connect attempts
Always use your language’s crypto / secrets / SecureRandom module.

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 POST requests 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/approved and /appstle/disconnect endpoints 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?
What should your app do?
  1. Validate the shop — check that this shop_domain exists in your system. If you don’t recognize the shop, return an error.
  2. Store the nonce and callback URL — save callback_nonce and callback_url associated with this shop_domain. You’ll need them to complete the handshake.
  3. Call back to Appstle — either immediately (auto-approve) or after merchant confirmation, call the callback_url to complete the connection. See Completing the handshake below.
  4. Return a success response — any 2xx status code tells Appstle the request was received.
Node.js (Express)

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?
What should your app do?
  1. Look up the stored nonce for this shop_domain
  2. Compare the callback_nonce from the request against your stored nonce
  3. If they match: delete the stored nonce (it’s single-use) and return { "verified": true }
  4. If they don’t match: return { "verified": false }
Node.js (Express)

Step 4: Implement the connect flow (your dashboard)

Now build the merchant-facing “Connect Appstle Subscriptions” 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.
1

Merchant clicks "Connect Appstle" in your dashboard

The merchant initiates the connection from inside your app’s UI.
2

Your app generates a cryptographically random nonce

Store it keyed by shop_domain with a 5-minute TTL.
3

Your app calls POST /api/partner/{id}/connect

Send the shop_domain, the callback_nonce, and your Partner Secret.
4

Appstle validates your Partner Secret

Appstle also confirms the shop has Appstle Subscriptions installed.
5

Appstle calls YOUR /appstle/verify endpoint

Payload: the shop_domain and the same callback_nonce.
6

Your /appstle/verify checks the nonce

Confirm it matches, delete it, return { "verified": true }.
7

Appstle returns pending_merchant_approval

The connection is pending — no access token has been issued yet.
8

Merchant approves in their Appstle dashboard

They open Settings → Partner Connections and click Approve.
9

Appstle creates a scoped API key

The token is POSTed to YOUR /appstle/approved endpoint.
10

Your app stores the access_token

Show “Connected!” to the merchant. You’re done.
Full implementation (Node.js):
curl equivalent:
Success response:
What happens next? The merchant will see a “Pending Request” in their Appstle dashboard under Settings → Partner Connections. (This menu appears automatically once a partner initiates a connection request — it is not visible before any partner has connected.) When they click “Approve,” Appstle creates a scoped API key and delivers it to your /appstle/approved endpoint (see Handling the approval callback below). Pending requests expire after 30 days if not acted on.
Deep link to approval screen: You can redirect the merchant directly to the approval screen to minimize friction:
Replace {shop-handle} with the merchant’s store handle (the part before .myshopify.com). This takes them straight to the pending connection for one-click approval. You can trigger this redirect in your UI immediately after receiving the pending_merchant_approval response.

Appstle-initiated connect (Flow B) — step by step

This is the flow where the merchant clicks “Connect” in Appstle’s dashboard.
1

Merchant clicks "Connect {YourApp}" in Appstle's dashboard

The connection is initiated from inside Appstle, not your UI.
2

Appstle calls POST /api/partner/{id}/initiate-connect

Internal Appstle call — your app is not involved yet.
3

Appstle generates a nonce (5-min TTL) and calls YOUR /appstle/connect

Payload: shop_domain, app, callback_url, and callback_nonce.
4

Your /appstle/connect stores the nonce and callback_url

Persist them keyed by shop_domain for the verify step.
5

Your app calls the callback_url (Appstle's /verify endpoint)

Send shop_domain, callback_nonce, and your Partner Secret.
6

Appstle verifies the nonce and issues a scoped API key

The access_token is returned in the response body.
7

Your app stores the access_token

Connection complete.
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:
Success response:
Failed response (nonce expired or mismatched):
You must call the verify endpoint within 5 minutes of receiving the nonce. After that, the nonce expires and the merchant will need to try again.

Using the API token

After a successful connection, your app has an access_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:
  • Subscription contractsGET /api/external/v2/subscription-contract-details
  • Customer subscriptionsGET /api/external/v2/subscription-customers/{customerId}
  • Update subscription statusPUT /api/external/v2/subscription-contracts-update-status (requires READ_WRITE)
  • Skip/Reschedule ordersPOST /api/external/v2/subscription-billing-attempts/skip-order/{id} (requires READ_WRITE)
  • Update line itemsPUT /api/external/v2/subscription-contracts-update-line-item (requires READ_WRITE)
  • Apply discountsPOST /api/external/v2/subscription-contracts-apply-discount (requires READ_WRITE)
  • And all other /api/external/v2/* endpoints
See the full Integration guide for complete endpoint documentation.

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 subscription data so it can be indexed alongside other store data.

How it works

During onboarding, you can configure a sync_path on your server (e.g., /appstle/sync). When subscription events occur (new subscriptions, cancellations, billing attempts, 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-Timestamp and X-Partner-Signature headers. Your app should verify the HMAC signature to confirm the request came from Appstle.
Verifying incoming HMAC signatures (Node.js):

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_path during onboarding — see below)
  • Your app should handle this gracefully and show a “Reconnect” option
Best practice: In your API client, check for 401 responses and update your UI to show the connection as disconnected:

Disconnect webhook (first-class endpoint)

Configure a disconnect_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:
If your partner uses HMAC-SHA256 auth, the webhook includes signed headers (X-Partner-Timestamp, X-Partner-Signature) so you can verify it came from Appstle. Your endpoint must:
  1. 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.
  2. 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.
  3. Mark the local connection inactive. Clear or null out the stored Appstle token so subsequent API calls don’t try to use it.
  4. Return 2xx even when there was nothing to do. A no-op disconnect is a successful disconnect from Appstle’s perspective.
This is a best-effort notification — your app should also handle 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):
Response:

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.
Why this matters: Older integrations sometimes inferred “connected” from the presence of a per-app API key column in their own database. That column is now a deprecated fallback — it can be stale (key revoked on Appstle’s side, your row never updated) and it can’t represent pending_merchant_approval or rejected. Always call /status before showing connection state to the merchant or making business decisions based on it.
Partners can authenticate with their Partner Secret or HMAC signature:
Response (active connection):
Response (pending merchant approval):
All possible status values:
Use the status endpoint to poll for approval if your app doesn’t implement the /appstle/approved callback. Poll every 30–60 seconds after initiating a connect. Once the status changes from pending_merchant_approval to active, your token has been delivered via the approval callback (or you can request it again).

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).
Your /appstle/approved endpoint must accept unauthenticated POST requests from Appstle’s servers. Do not put authentication middleware (e.g., JWT validation, API key checks) on this endpoint — Appstle will not send your app’s auth credentials when calling this callback. If you need to verify the request is from Appstle, use HMAC-SHA256 authentication mode — when enabled, the callback includes signed headers (X-Partner-Timestamp, X-Partner-Signature) you can verify.
Request body from Appstle (Nonce Handshake mode):
Request body from Appstle (Simple Token Exchange mode):
In Simple Token Exchange mode, your app already provided its own token during the connect call. The approval callback simply confirms the connection is now active — Appstle will start using your token for API calls.
Expected response: Return any 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. If your partner uses HMAC-SHA256 auth, the callback includes signed headers (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:
  1. Poll the status endpoint — check GET /api/partner/{id}/status?shop_domain=... until the status is active
  2. 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 to rejected 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/approved calls 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 2xx even when there is nothing to do.
  • Status reads: safe by definition — no side effects.
If your code is built on “this only ever fires once”, expect bugs the first time the merchant flips connect/disconnect quickly or the first time a network blip triggers an Appstle retry.

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_domain is validated in your /appstle/connect and /appstle/verify endpoints — 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/disconnect endpoint cleans up stored tokens and marks the connection as inactive

Complete example: partner-initiated flow

FAQ

Yes. Each partner gets its own scoped API token. Merchants can connect as many partners as they want. The tokens are completely independent.
All active partner connections for that shop are automatically disconnected. Your tokens will stop working (401 responses).
Yes — contact the Appstle team. New connections will use the updated permission, but existing connections keep their original permission until reconnected.
Partner tokens share the same rate limits as regular API keys. If you receive a 429 Too Many Requests, implement exponential backoff.
Use a Shopify development store with Appstle Subscriptions installed. The partner integration works identically in development and production. You can use a tool like ngrok to expose your local endpoints to the internet for testing.
The merchant simply needs to click “Connect” again. A new nonce will be generated. Old nonces are automatically cleaned up.
Yes. Flow A is for when the merchant connects from your dashboard. Flow B is for when they connect from Appstle’s dashboard. Both are needed for a complete integration. You also need the /appstle/approved endpoint to receive API tokens after merchant approval (Flow A).
No. A new connect handshake requires the merchant to initiate it from one of the dashboards. This is by design — merchants must explicitly authorize each connection.
For security and trust. When your app initiates a connection, the merchant hasn’t explicitly agreed on Appstle’s side. The approval step ensures merchants consciously grant API access to partner apps. Appstle-initiated connections (Flow B) skip this step because the merchant is already clicking “Connect” in the Appstle dashboard.
Pending connection requests expire after 30 days. If the merchant doesn’t approve or reject within that window, the request expires and your app will need to initiate a new connection.
The status changes to 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?