# Convert a Salla Shipping App to a Matjrah Shipping App

> Audience: coding agents, courier engineering teams and integration partners adapting an existing Salla Shipping App to Matjrah.

> For the installable workflow, source scanner, evidence templates and validators, download https://developers.matjrah.com/skills/port-salla-app-to-matjrah.zip and invoke `$port-salla-app-to-matjrah`.

This is an evidence-first migration playbook. It is not an API-compatibility claim and it is not permission to replace working Salla code. Preserve the proven carrier layer and add a separate Matjrah platform adapter.

## Sources of truth

- Matjrah visual Shipping App guide: https://developers.matjrah.com/guides/shipping-integration/en/
- Matjrah API reference: https://developers.matjrah.com/docs
- Developer Center: https://developers.matjrah.com/login
- General Salla-to-Matjrah playbook: https://developers.matjrah.com/agents/salla-to-matjrah.md
- Integration support: dev@matjrah.com
- Partnerships call: https://calendly.com/matjrah/30min

When this file and the live Matjrah API reference differ, stop and follow the live reference. Never infer a Matjrah endpoint or payload field from a similarly named Salla contract.

## The migration boundary

Reuse the existing shipping core:

- carrier authentication and carrier API client;
- service-code and coverage mapping;
- AWB and label generation;
- tracking-state normalization;
- cancellation and return rules;
- queues, retries, reconciliation, monitoring and support tooling.

Replace the commerce-platform edge:

- Salla installation/OAuth lifecycle;
- Salla merchant-token persistence and refresh behavior;
- Salla Webhook verification and event envelopes;
- Salla shipment/order payload mapping;
- Salla status, label and tracking callbacks;
- platform-specific scopes, errors, rate limits and tests.

Target shape:

```text
Salla platform adapter ───┐
                          ├── platform-neutral shipping service ── carrier API
Matjrah Shipping adapter ─┘
```

Do not expose either platform's payload types inside the shared shipping service. Normalize to explicit internal installation, shipment, parcel, recipient, item, COD, label and tracking types.

## Non-negotiable rules

- Shipping on Matjrah always uses an approved, installed Shipping App created in the Developers Center. Do not implement direct merchant dashboard API/Webhook credentials for shipping.
- Do not delete or rewrite the Salla adapter during discovery.
- Do not search-and-replace URLs, event names, signatures or payload fields.
- Verify the exact raw Matjrah Webhook body before JSON parsing.
- Persist `request_id` and `shipment_id` before calling the carrier.
- A repeated delivery must never create a second carrier shipment or AWB.
- Encrypt each `ait_…` installation token at rest and isolate it by Matjrah store and installation.
- Use only the token belonging to the shipment's installation.
- Reuse the same idempotency key for the same logical Matjrah mutation retry.
- Never log tokens, signing secrets, raw recipient data or label credentials.
- Never send production secrets, customer data or real payloads to an AI tool unless the organization approved that tool and its data controls.
- Mark unknown or unsupported behavior in `gaps.md`; do not fabricate compatibility.

## Required discovery output

Before editing, create `inventory.md` with file-and-line evidence for:

1. Salla app installation and OAuth callbacks.
2. Access/refresh token storage and refresh jobs.
3. Every Salla shipment/order event consumed.
4. The exact Salla signature-verification code.
5. Every carrier create, label, tracking, cancellation and return call.
6. Shipment ownership and deduplication keys.
7. Queues, retries, dead letters, reconciliation and scheduled jobs.
8. Status normalization and order-status callbacks.
9. Tenant/merchant credential isolation.
10. Unit, fixture, integration and end-to-end test commands.

Also produce `mapping.md`:

```text
shipping capability | current Salla contract | Matjrah contract | reusable core | code owner | migration state | evidence
```

Allowed states: `supported`, `supported_with_mapping`, `redesign_required`, `blocked`, `unknown_needs_evidence`.

## Matjrah Shipping App contract to implement

The app lifecycle and shipment runtime are part of an installed Shipping App:

```text
signed app.installed
  → encrypt per-store ait_ token
  → validate installation with GET /ping
  → signed shipment.creating
  → durable request_id + shipment_id claim
  → normalized internal shipment
  → existing carrier create-shipment service
  → PUT /v1/shipments/{id} with AWB/tracking/label
  → PUT /v1/shipments/{id}/track for lifecycle updates
  → POST /v1/shipments/{id}/cancel when cancellation applies
```

The `shipment.creating` handler must explicitly map:

- installation and shipment identity;
- `direction: forward | return`;
- recipient and destination fields;
- parcels/items and weight;
- selected `carrier_code` or service identity;
- COD amount and currency;
- any documented reference fields required by the carrier.

Do not assume the event is shaped like a Salla event. Add a sanitized Matjrah fixture and map every consumed field explicitly.

## Required implementation passes

### Pass 1 — preserve and isolate

Keep the current Salla adapter passing its existing tests. Extract shared carrier behavior only when its current ownership is proven. Add a separate `MatjrahShippingAdapter` or equivalent boundary.

### Pass 2 — installation and secrets

Implement raw-body signature verification, durable `request_id` deduplication, encrypted `ait_…` storage, `/ping` validation and uninstall revocation. Do not port the Salla OAuth callback or refresh-token scheduler into the Matjrah path.

### Pass 3 — one shipment vertical slice

Handle one sanitized `shipment.creating` fixture. Claim the delivery durably before calling the existing carrier service. Persist the carrier shipment reference, AWB, label and tracking result against the Matjrah `shipment_id`.

### Pass 4 — idempotent response

Attach the AWB, tracking number, stable tracking link and optional label through the documented Matjrah shipment endpoint. Retry a lost response with the same idempotency key. Treat an idempotent replay as success.

### Pass 5 — lifecycle parity

Map carrier states to the documented Matjrah shipment states. Add cancellation and return behavior only after forward-shipment creation is proven. Preserve terminal-state and retry rules.

### Pass 6 — isolation and failure recovery

Prove store A cannot select store B's token, shipment, label or queue job. Test invalid signature, duplicate event, revoked token, missing scope, rate limit, carrier timeout, lost callback response and worker restart.

### Pass 7 — Sandbox and active test store

Use self-service Sandbox for installation and signed sample-event delivery. Use a provisioned active test store for the real gateway, carrier call, AWB attachment, tracking, cancellation and merchant-visible behavior. A sample event or HTTP 200 alone is not certification.

## Focused 24-hour prototype

When the Salla adapter is clean and the carrier create-shipment API already works, an experienced engineer with an approved AI coding agent can often prototype this narrow slice in one focused day:

1. `inventory.md`, `mapping.md`, `gaps.md`, `test-plan.md`.
2. Signed Matjrah installation and isolated token storage.
3. One sanitized `shipment.creating` fixture.
4. One existing carrier create-shipment call.
5. One idempotent Matjrah AWB/label response.

This excludes production rollout, full service-manifest configuration, every carrier service, cancellation/returns, monitoring hardening, certification and merchant acceptance.

## Minimum test plan

- [ ] Existing Salla adapter tests still pass.
- [ ] Valid `app.installed` creates one isolated Matjrah installation.
- [ ] Modified raw body fails signature verification.
- [ ] Duplicate `request_id` is acknowledged without a second carrier call.
- [ ] Duplicate `shipment_id` cannot create another AWB.
- [ ] Store A cannot use store B's token or shipment.
- [ ] Forward and return directions map explicitly.
- [ ] COD amount and currency are preserved exactly.
- [ ] Carrier timeout is retryable without duplicate creation.
- [ ] AWB/label retry reuses one idempotency key.
- [ ] Tracking states map to documented Matjrah states.
- [ ] Revoked token and missing scope stop unsafe retries.
- [ ] Logs contain no token, secret, raw recipient payload or label credential.
- [ ] Sandbox signed delivery is evidenced separately from active-store gateway behavior.

## Copy-ready prompt for a coding agent

```text
Read https://developers.matjrah.com/agents/salla-shipping-to-matjrah.md and the live Matjrah API reference at https://developers.matjrah.com/docs.

Goal: add a Matjrah Shipping App adapter beside this repository's existing Salla Shipping App adapter. Preserve the existing Salla integration and reuse the proven carrier API, AWB, label, tracking, cancellation, return, queue and monitoring logic.

Shipping boundary:
- Matjrah shipping must run through an approved, installed Shipping App; do not implement direct merchant API/Webhook credentials.
- Replace only installation/auth, Webhook verification, platform payload mapping, scopes, callbacks and platform-specific tests.
- Do not invent endpoints, fields, events or compatibility.
- Do not expose secrets or production customer data.

Before editing, produce inventory.md, mapping.md, gaps.md and test-plan.md with file-and-line evidence. Then implement only this vertical slice:

signed app.installed
→ isolated encrypted ait_ token
→ GET /ping
→ signed shipment.creating
→ durable request_id + shipment_id deduplication
→ explicit internal Shipment mapping
→ existing carrier create-shipment service
→ one idempotent AWB/tracking/label response to Matjrah

Add tests for invalid signature, duplicate delivery, duplicate shipment, tenant isolation, carrier timeout and lost-response retry. Keep the same idempotency key for the same logical mutation. Report implemented, preserved, verified, blocked and not-yet-proven states separately. Do not claim production or certification readiness from unit tests, Sandbox delivery or HTTP 200 alone.
```

For contract questions, email dev@matjrah.com or schedule https://calendly.com/matjrah/30min.
