0% found this document useful (0 votes)
4 views9 pages

Merchant Doc API

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views9 pages

Merchant Doc API

Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

SubscriptionPro — Merchant API Integration Guide

Version: 1.0 | Last Updated: April 26, 2026

This guide explains how to build a Merchant API that connects your product to SubscriptionPro. After integrating, your customers can purchase your product
through SubscriptionPro, and licenses will be generated automatically.

How It Works (Big Picture)

sequenceDiagram
participant C as Customer
participant SP as SubscriptionPro
participant M as Your Merchant API

C->>SP: Clicks "Buy Product"


SP->>M: Redirect customer to /authorize
M->>C: Shows "Authorize Access" page
C->>M: Clicks "Authorize"
M->>SP: Redirects back with ?code=xxx
SP->>M: POST /token (exchange code for access_token)
M->>SP: Returns access_token
Note over SP: Customer completes payment on SP
SP->>M: POST /license/activate (with access_token)
M->>SP: Returns license_key, status, expiry
Note over SP: Order created with license

In simple terms:

1. Customer clicks "Buy" on SubscriptionPro


2. Customer is redirected to your website to authorize access
3. After authorization, SubscriptionPro gets a token from your API
4. After payment, SubscriptionPro calls your API to generate a license
5. The license is shown to the customer in their order dashboard

What You Need to Build


Your API needs these 8 endpoints . Below is exactly what each one should do.

# Method Endpoint Purpose

1 GET /api/authorize Show authorization page to customer

Customer clicks "Authorize", redirect back with


2 GET /api/authorize/confirm
code

3 POST /api/token Exchange auth code for access token

4 POST /api/license/activate Generate a license after payment

5 POST /api/license/validate Check if a license key is valid

6 GET /api/profile Get customer profile

7 GET /api/billing Get billing history

8 POST /api/cancel Cancel subscription and revoke license

[!TIP] The paths after /api/ can be customized. You'll configure them in the SubscriptionPro merchant dashboard when setting up your product.

Step 1: Database Tables


You'll need these tables in your database:

customers — Stores customer data from SubscriptionPro

CREATE TABLE customers (


id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
email VARCHAR(255) UNIQUE,
access_token VARCHAR(255) UNIQUE NULL,
product_identifier VARCHAR(255) NULL,
sp_customer_id BIGINT UNSIGNED NULL COMMENT 'Customer ID from SubscriptionPro',
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL
);

oauth_codes — Temporary authorization codes

CREATE TABLE oauth_codes (


id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
code VARCHAR(255),
client_id VARCHAR(255) DEFAULT 'subscriptionpro',
product_identifier VARCHAR(255) NULL,
customer_id BIGINT UNSIGNED NULL,
used BOOLEAN DEFAULT FALSE,
expires_at TIMESTAMP NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL
);

licenses — License keys generated for customers

CREATE TABLE licenses (


id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
customer_id BIGINT UNSIGNED,
plan_name VARCHAR(255),
license_key VARCHAR(255) UNIQUE,
product_identifier VARCHAR(255),
status VARCHAR(50) DEFAULT 'active' COMMENT 'active, cancelled, expired, revoked',
activated_at TIMESTAMP NULL,
expires_at TIMESTAMP NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL
);

billing_records — Payment history

CREATE TABLE billing_records (


id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
customer_id BIGINT UNSIGNED,
plan_name VARCHAR(255),
amount DECIMAL(10,2),
transaction_id VARCHAR(255),
status VARCHAR(50) DEFAULT 'paid',
billed_at TIMESTAMP NULL,
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL
);

Step 2: Build Your Endpoints


2.1 — Authorization Page

GET /api/authorize

SubscriptionPro redirects the customer's browser to this URL. You show a page asking them to authorize access.

Query Parameters:

Parameter Type Description

Your product's unique ID in


product_identifier string
SubscriptionPro

redirect_uri string URL to redirect back to after authorization

What to do:

1. Show an HTML page with your branding


2. Display what permissions SubscriptionPro is requesting
3. Include an "Authorize" button that submits to /api/authorize/confirm
4. Include a "Deny" button that redirects back to redirect_uri

Example response: Return an HTML page (not JSON).

2.2 — Confirm Authorization

GET /api/authorize/confirm

Called when the customer clicks "Authorize". You generate a one-time code and redirect back to SubscriptionPro.

Query Parameters: Same as above ( product_identifier , redirect_uri )

What to do:

1. Generate a random code (e.g., 40 characters)


2. Save it to oauth_codes table with used = false and expires_at = now + 10 minutes
3. Redirect the customer to: {redirect_uri}?code={code}&product_identifier={product_identifier}

Example (PHP/Laravel):

public function authorizeConfirm(Request $request)


{
$code = Str::random(40);

OauthCode::create([
'code' => $code,
'product_identifier' => $request->product_identifier,
'used' => false,
'expires_at' => now()->addMinutes(10),
]);

$separator = str_contains($request->redirect_uri, '?') ? '&' : '?';


return redirect(
$request->redirect_uri . $separator
. "code={$code}&product_identifier={$request->product_identifier}"
);
}

2.3 — Token Exchange

POST /api/token

SubscriptionPro's backend calls this to exchange the one-time code for a long-lived access token.

Request Body (JSON):


{
"code": "abc123xyz...",
"product_identifier": "your-product-id",
"customer_id": 42
}

What to do:

1. Look up the code in oauth_codes — check it's not used, not expired
2. Mark the code as used = true
3. Create or update a customer record with a new access_token
4. Return the token

Response (JSON):

{
"access_token": "your_generated_token_here",
"refresh_token": "optional_refresh_token",
"token_type": "Bearer",
"customer_id": 1,
"expires_in": 31536000
}

[!IMPORTANT] The access_token is stored by SubscriptionPro and used for all future API calls. Make it long-lived (1 year recommended).

2.4 — License Activation (Most Important)

POST /api/license/activate

Called automatically by SubscriptionPro after a successful payment. This is where you generate the license key.

Request Body (JSON):

{
"access_token": "the_customers_token",
"plan_name": "Monthly Plan",
"product_identifier": "your-product-id",
"amount": 9.99
}

What to do:

1. Validate the access_token — find the customer


2. Generate a unique license key
3. Save it to licenses table with status = active
4. Return the license details

Response (JSON):

{
"success": true,
"license_key": "ABCDE-FGHIJ-KLMNO-PQRST",
"plan_name": "Monthly Plan",
"status": "active",
"activated_at": "2026-04-26T12:00:00.000000Z",
"expires_at": "2027-04-26T12:00:00.000000Z"
}

[!CAUTION] If this endpoint fails or returns an error, the customer's order will be created without a license . Make sure this endpoint is reliable.

Example (PHP/Laravel):
public function licenseActivate(Request $request)
{
$customer = Customer::where('access_token', $request->access_token)->first();

if (!$customer) {
return response()->json(['error' => 'Invalid access token'], 401);
}

// Generate a unique license key (format: XXXXX-XXXXX-XXXXX-XXXXX)


$licenseKey = strtoupper(implode('-', str_split(Str::random(20), 5)));

$license = License::create([
'customer_id' => $customer->id,
'plan_name' => $request->plan_name,
'license_key' => $licenseKey,
'product_identifier' => $request->product_identifier,
'status' => 'active',
'activated_at' => now(),
'expires_at' => now()->addYear(), // or addMonth() for monthly
]);

return response()->json([
'success' => true,
'license_key' => $licenseKey,
'plan_name' => $request->plan_name,
'status' => 'active',
'activated_at' => $license->activated_at->toISOString(),
'expires_at' => $license->expires_at->toISOString(),
]);
}

2.5 — License Validation

POST /api/license/validate

Checks if a license key is valid. Can be called by anyone with the key (no auth required).

Request Body:

{
"license_key": "ABCDE-FGHIJ-KLMNO-PQRST"
}

Response (valid):

{
"valid": true,
"license_key": "ABCDE-FGHIJ-KLMNO-PQRST",
"status": "active",
"plan_name": "Monthly Plan",
"product_identifier": "your-product-id",
"activated_at": "2026-04-26T12:00:00.000000Z",
"expires_at": "2027-04-26T12:00:00.000000Z",
"message": "License is valid and active."
}

Response (invalid):

{
"valid": false,
"message": "License key not found."
}
2.6 — Customer Profile

GET /api/profile

Returns customer info and their active license. Pass access_token as a Bearer header or query parameter.

Response:

{
"id": 1,
"name": "John Doe",
"email": "john@[Link]",
"product_identifier": "your-product-id",
"sp_customer_id": 42,
"active_license": {
"license_key": "ABCDE-FGHIJ-KLMNO-PQRST",
"plan_name": "Monthly Plan",
"status": "active",
"expires_at": "2027-04-26T12:00:00.000000Z"
}
}

2.7 — Billing History

GET /api/billing

Returns all billing records for the customer.

Response:

{
"billing": [
{
"id": 1,
"plan_name": "Monthly Plan",
"amount": 9.99,
"transaction_id": "TXN_ABC123",
"status": "paid",
"billed_at": "2026-04-26T12:00:00.000000Z"
}
]
}

2.8 — Cancel Subscription

POST /api/cancel

Called when a customer cancels their subscription on SubscriptionPro. You should revoke their active licenses.

Request Body:

{
"access_token": "the_customers_token"
}

Response:

{
"success": true,
"message": "Subscription cancelled successfully."
}

Step 3: Configure Your Product in SubscriptionPro


When creating your product in the SubscriptionPro merchant dashboard, enable "API Integration" and fill in these URLs:

Field What to enter Example

Webhook (Base URL) Your API's base URL [Link]

Authorization URL Path for OAuth page authorize

License Activation
Path for license generation license/activate
URL

Payment URL Path for payment recording payment

Profile URL Path for customer profile profile

Billing URL Path for billing history billing

Cancel URL Path for cancellation cancel

[!NOTE] The Webhook base URL is combined with each path. For example, if your webhook is [Link] and license activation URL
is license/activate , SubscriptionPro will call [Link] .

Step 4: Test Your Integration

Quick Test with cURL

1. Get a Token (simulate):

curl -X POST [Link] \


-H "Content-Type: application/json" \
-d '{"code":"test123", "product_identifier":"your-product-id", "customer_id": 1}'

2. Activate a License:

curl -X POST [Link] \


-H "Content-Type: application/json" \
-d '{
"access_token": "TOKEN_FROM_STEP_1",
"plan_name": "Monthly Plan",
"product_identifier": "your-product-id",
"amount": 9.99
}'

3. Validate the License:

curl -X POST [Link] \


-H "Content-Type: application/json" \
-d '{"license_key": "LICENSE_KEY_FROM_STEP_2"}'

Error Handling

All endpoints should return proper HTTP status codes:

Status Meaning When to use

200 Success Request completed successfully

400 Bad Request Missing or invalid parameters

401 Unauthorized Invalid or missing access token


Status Meaning Resource
When not found (e.g., invalid license
to use
404 Not Found
key)

500 Server Error Something went wrong on your end

Error response format:

{
"error": "Description of what went wrong"
}

Security Best Practices

[!WARNING] Follow these to keep your API secure:

1. Always validate access tokens — Never trust the token without checking your database
2. Use HTTPS — All API calls should be over HTTPS in production
3. Expire authorization codes quickly — 10 minutes maximum
4. Mark codes as used — Prevent code replay attacks
5. Generate unique license keys — Use cryptographically random strings
6. Rate limit your endpoints to prevent abuse

Complete Laravel Starter


Want a head start? Here's a complete Laravel controller you can copy:

# Create a new Laravel project


composer create-project laravel/laravel my-merchant-api
cd my-merchant-api

# Create your migrations


php artisan make:migration create_customers_table
php artisan make:migration create_oauth_codes_table
php artisan make:migration create_licenses_table
php artisan make:migration create_billing_records_table

# Create your models


php artisan make:model Customer
php artisan make:model OauthCode
php artisan make:model License
php artisan make:model BillingRecord

# Create the controller


php artisan make:controller MerchantController

Then add your routes in routes/[Link] :

use App\Http\Controllers\MerchantController;

Route::get('/authorize', [MerchantController::class, 'showAuthorizePage']);


Route::get('/authorize/confirm', [MerchantController::class, 'authorizeConfirm']);
Route::post('/token', [MerchantController::class, 'token']);
Route::post('/license/activate', [MerchantController::class, 'licenseActivate']);
Route::post('/license/validate', [MerchantController::class, 'licenseValidate']);
Route::get('/profile', [MerchantController::class, 'profile']);
Route::get('/billing', [MerchantController::class, 'billing']);
Route::post('/cancel', [MerchantController::class, 'cancel']);

Need Help?
Check the Demo Merchant API source code for a complete working example
Contact SubscriptionPro support for integration assistance
Make sure your Webhook base URL is accessible from the internet (not localhost)

You might also like