Building a Plugin
Scaffold
npx carphacom-cli create plugin --type=payment --id=my-pay
cd my-pay
npm install
Generated layout:
my-pay/
src/
index.ts # entrypoint — exports register(), unregister()
provider.ts # for payment/fulfillment plugins
admin/page.tsx # for admin-extension plugins
manifest.json
package.json
tsconfig.json
README.md
Implement the entrypoint
// src/index.ts
import type { CarphaPlugin } from "@carphacom/sdk"
const plugin: CarphaPlugin = {
async register({ medusa, config }) {
// Wire up routes, providers, migrations
},
async unregister() {
// Cleanup if needed
},
}
export default plugin
Add a payment provider
// src/provider.ts
import { AbstractPaymentProvider } from "@medusajs/framework"
export class StripeLikeProvider extends AbstractPaymentProvider {
static identifier = "my-pay"
async initiatePayment(input) { /* ... */ }
async authorizePayment(input) { /* ... */ }
async capturePayment(input) { /* ... */ }
async refundPayment(input) { /* ... */ }
async cancelPayment(input) { /* ... */ }
async retrievePayment(input) { /* ... */ }
}
Reference it from manifest.json:
"medusa_provider": {
"module": "payment",
"resolve": "./dist/provider.js",
"id": "my-pay"
}
Local development against a real instance
- Symlink:
cd /opt/carphacom/installed && ln -s ~/dev/my-pay my-pay - Insert a row directly in
carphacom_plugin(statusinstalled, manifest copied from yourmanifest.json). pm2 restart carphacom-backend.- Edit code, rebuild (
npm run build),pm2 restart carphacom-backendagain.
Build for distribution
npm run build # tsc / rollup → dist/
npm pack # produces my-pay-1.0.0.tgz
zip -r my-pay-1.0.0.zip dist/ manifest.json package.json README.md
Sign the package
npx carphacom-cli sign my-pay-1.0.0.zip --key ~/.carphacom/dev-key.ed25519
This emits my-pay-1.0.0.zip.sig. Both files go to the marketplace. Tenant installers verify
the signature against carphacom.com's published vendor public keys before installing.