Skip to content

Error Codes Reference

All API errors follow a consistent bilingual format. The message field is automatically localized based on the Accept-Language header.

Error Response Structure

json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "English error message",
    "details": [
      { "path": "fieldName", "message": "Field-specific error" }
    ]
  }
}

Arabic (Accept-Language: ar):

json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "رسالة الخطأ بالعربية",
    "details": [
      { "path": "fieldName", "message": "خطأ خاص بالحقل" }
    ]
  }
}

The details field is optional and only included for validation errors with field-level information.


Authentication Errors (401 / 403 / 502)

CodeStatusEnglish MessageArabic MessageCondition
AUTH_REQUIRED401Authentication requiredيلزم المصادقةMissing or invalid token
AUTH_SESSION_EXPIRED401Session has expiredانتهت صلاحية الجلسةExpired JWT
AUTH_ACCOUNT_DEACTIVATED401Account is deactivatedالحساب معطلSign-in blocked at OTP verification for a deactivated account (admin deactivation or account-deletion soft-delete)
AUTH_INVALID_OTP401Invalid OTP codeرمز التحقق غير صحيحWrong OTP or unregistered phone/email
AUTH_EXPIRED_OTP401OTP has expiredانتهت صلاحية رمز التحققOTP TTL exceeded (300s), or the maximum verification attempts for the OTP were exceeded
AUTH_NO_CREDENTIAL401At least one of phone or email is requiredيلزم توفير رقم الهاتف أو البريد الإلكترونيNeither phone nor email provided
AUTH_PHONE_EXISTS401Phone number already registeredرقم الهاتف مسجل مسبقاًDuplicate phone on registration
AUTH_EMAIL_EXISTS401Email already registeredالبريد الإلكتروني مسجل مسبقاًDuplicate email on registration
AUTH_CONSENT_REQUIRED401Required consent types missingأنواع الموافقة المطلوبة ناقصةInvalid or missing consent entries
AUTH_RATE_LIMIT_EXCEEDED401Too many OTP requests, please try again laterطلبات كثيرة للتحقق، يرجى المحاولة لاحقاًPer-recipient OTP request throttle. More than 3 OTP requests were sent to the same phone or email within the 15-minute window (register, login, or change-phone). This is separate from verification-attempt limiting, which is reported under AUTH_EXPIRED_OTP instead
AUTH_PHONE_UPDATE_FAILED502Failed to update phone numberفشل تحديث رقم الهاتفThe phone-change OTP was verified, but persisting the new phone number failed. This happens if the local database update itself fails, or if it succeeds but the following Supabase Auth update fails (the local change is then rolled back)
AUTH_BLOCKLISTED403User or device is blocklistedالمستخدم أو الجهاز محظورBlocklist check
FORBIDDEN401Insufficient permissions — super_admin requiredصلاحيات غير كافية — مطلوب super_adminNon-super_admin on compliance routes
AUTH_FORBIDDEN403Insufficient permissionsصلاحيات غير كافيةRole/area guard denied the request (non-super_admin on /admin/users, or a user lacking the required area on an area-gated route)

AUTH_INVALID_OTP is used generically for both wrong OTP and unregistered phone/email to prevent enumeration attacks.

AUTH_PHONE_EXISTS is 401 here (thrown as an AuthError on /auth/register) but 409 on /auth/change-phone and /auth/verify-change-phone (thrown there as a plain AppError) — see Authentication.

FORBIDDEN (compliance routes) is thrown as an AuthError, whose constructor only maps the exact code AUTH_FORBIDDEN to 403 — every other code, including the distinct string FORBIDDEN, resolves to 401. So despite the "super_admin required" message, this code actually returns 401, not 403.


Validation Errors (400)

CodeStatusEnglish MessageCondition
VALIDATION_ERROR400Validation failedZod schema validation failed. details array contains field-specific errors.
VALIDATION_ICCID_INVALID400ICCID must be exactly 19 digitsICCID format validation failed
VALIDATION_SIM_LIMIT_EXCEEDED400SIM limit exceeded for your identity typeCITC SIM limit per identity type exceeded

Validation Error Details Example

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": [
      { "path": "phone", "message": "Phone must be Saudi format +966XXXXXXXXX" },
      { "path": "iccid", "message": "ICCID must contain only digits" }
    ]
  }
}

Not Found Errors (404)

CodeStatusEnglish MessageArabic MessageCondition
NOT_FOUND404Resource not foundالمورد غير موجودGeneric not found
PACKAGE_NOT_FOUND404Package not foundالباقة غير موجودةPackage ID not found or inactive
ACTIVATION_NOT_FOUND404Activation not foundالتفعيل غير موجودActivation ID not found or not owned by user

Administration User Errors (404 / 409 / 502)

Returned by the super_admin-only /admin/users endpoints. See Admin Users.

CodeStatusEnglish MessageArabic MessageCondition
ADMIN_USER_NOT_FOUND404Administration user not foundمستخدم الإدارة غير موجودNo manageable user with the given id (owners and end users are not manageable)
ADMIN_USER_PHONE_EXISTS409Phone number already registeredرقم الهاتف مسجل بالفعلPhone already in use on create
ADMIN_USER_EMAIL_EXISTS409Email address already registeredالبريد الإلكتروني مسجل بالفعلEmail already in use on create
ADMIN_USER_CREATE_FAILED502Failed to create user accountفشل إنشاء حساب المستخدمAuth account creation failed upstream
ADMIN_USER_PROFILE_NOT_CREATED502Failed to create user profileفشل إنشاء الملف الشخصي للمستخدمProfile row was not seeded; the orphaned auth identity is rolled back
ADMIN_USER_DELETE_FAILED502Failed to remove userفشل حذف المستخدمAuth identity removal failed upstream

Company Errors (403 / 404 / 409 / 502)

Returned by the B2B company registration, portal, and admin-oversight endpoints. See B2B Portal and B2B Admin.

CodeStatusEnglish MessageArabic MessageCondition
COMPANY_NOT_FOUND404Company not foundالشركة غير موجودةNo company with the given id
COMPANY_ALREADY_REGISTERED409You already belong to a companyأنت مرتبط بشركة بالفعلCaller already has a company membership
COMPANY_CR_EXISTS409CR number already registeredرقم السجل التجاري مسجل بالفعلCommercial registration number already in use
COMPANY_CREATE_FAILED502Failed to register companyفشل تسجيل الشركةCompany registration failed
COMPANY_INVALID_TRANSITION409Cannot {action} a {status} companyإجراء غير صالح لحالة الشركة الحاليةThe status action (approve, reject, suspend, reactivate) is not valid for the company's current status
COMPANY_NOT_APPROVED403Company is pending approvalالشركة في انتظار الموافقةPortal route accessed by a member of a not-yet-approved company (also returned, with a different message, when a magic link is redeemed for — or POST /activations is attempted against — a company that isn't approved)
COMPANY_SUSPENDED403Company access is suspendedتم تعليق وصول الشركةPortal route accessed by a member of a suspended company
COMPANY_REJECTED403Company registration was rejectedتم رفض تسجيل الشركةPortal route accessed by a member of a rejected company
COMPANY_NOT_READY409This company isn't ready to send activation links yet — the contract and payment must be confirmed firstهذه الشركة غير جاهزة لإرسال روابط التفعيل بعد — يجب تأكيد العقد والدفع أولاًMagic links minted before the contract + payment readiness gate is satisfied
COMPANY_BALANCE_EXCEEDED409This activation would exceed your company's available balanceسيؤدي هذا التفعيل إلى تجاوز الرصيد المتاح لشركتكFlexible balance gate: drawn funds plus this seat's charge would pass the company's funded amount (also appears as a per-row code in the link-send failed array)

Quote Errors (400 / 404 / 409 / 502)

Returned by the B2B quote lifecycle endpoints. See B2B Portal and B2B Admin.

CodeStatusEnglish MessageArabic MessageCondition
QUOTE_NOT_FOUND404Quote not foundالطلب غير موجودNo quote with the given id (or, on the admin read, the quote is still a private draft)
QUOTE_INVALID_STATE409Varies with the action (e.g. "Quote has no items to confirm")يختلف حسب الإجراءThe quote's status doesn't allow the requested action
QUOTE_CREATE_FAILED502Failed to create quoteفشل إنشاء الطلبQuote draft creation failed
QUOTE_VERSION_SUPERSEDED409A newer version has superseded this oneاستُبدلت هذه النسخة بنسخة أحدثAction attempted on a quote version that a counter has since superseded
QUOTE_COUNTER_FAILED502Failed to create the countered versionفشل إنشاء النسخة المعدَّلةCountering a quote failed
QUOTE_PACKAGE_NOT_FOUND400One or more packages do not exist or are not available for business ordersباقة واحدة أو أكثر غير موجودة أو غير متاحة لطلبات الأعمالA quote line references a package id that doesn't exist or is not B2B-orderable (inactive, or no B2B price — the same surface the B2B catalog exposes). The offending ids are in error.details.packageIds

Contract Errors (400 / 404 / 409 / 502)

Returned by the B2B contract confirmation and payment endpoints. See B2B Portal and B2B Admin.

CodeStatusEnglish MessageArabic MessageCondition
CONTRACT_NOT_FOUND404Contract not foundالعقد غير موجودNo contract with the given id
CONTRACT_ALREADY_EXISTS409This company already has an active contractيوجد لدى هذه الشركة عقد نشط بالفعلConfirming a quote for a company that already has an active contract
CONTRACT_ITEM_NOT_FOUND404Contract line not found on this company's active contractبند العقد غير موجود ضمن العقد النشط لهذه الشركةA roster package assignment references a contract line that doesn't belong to the company's active contract
CONTRACT_PACKAGE_PRICE_MISSING400One or more quoted packages have no B2B price set — cannot confirm this contractباقة واحدة أو أكثر في طلب تحديد الباقات لا تملك سعر أعمال محدد — لا يمكن تأكيد هذا العقدConfirming a quote where a quoted package has no priceSarB2b
CONTRACT_CREATE_FAILED502Failed to create contractفشل إنشاء العقدContract creation failed
CONTRACT_PAYMENT_MODE_INVALID409Payments cannot be recorded for this contractلا يمكن تسجيل الدفعات لهذا العقدRecording a payment on a contract whose payment mode is neither prepaid nor flexible (legacy/invalid data — every contract is one or the other today)
CONTRACT_PAYMENT_BELOW_TOTAL409Payment amount is below the contract totalقيمة الدفعة أقل من إجمالي العقدRecorded payment amount is less than the contract's totalSar
CONTRACT_PAYMENT_IDEMPOTENCY_CONFLICT409This idempotency key was already used for a different paymentمفتاح العملية مستخدم بالفعل لدفعة مختلفةThe same idempotencyKey was replayed with a different method or amount — replaying it with identical values returns the original record instead
CONTRACT_PAYMENT_DOCUMENT_INVALID_MIME400Unsupported document typeنوع المستند غير مدعومThe uploaded payment document's MIME type isn't accepted
CONTRACT_PAYMENT_DOCUMENT_TOO_LARGE400Document must be 5MB or lessيجب ألا يتجاوز حجم المستند 5 ميغابايتThe uploaded payment document exceeds the 5MB size cap
CONTRACT_PAYMENT_RECORD_FAILED502Failed to record paymentفشل تسجيل الدفعةRecording the payment failed
CONTRACT_PAYMENT_DOCUMENT_NOT_FOUND404Payment document not foundمستند الدفع غير موجودThe payment record has no supporting document to download

Roster Errors (404 / 409)

The B2B CSV roster staging endpoint returns no error envelope of its own. Row-level problems — invalid phone or email, a duplicate contact, or a contact a concurrent upload claimed first — come back as data in the rejected array of a 200 response. The same holds for the batch link routes, whose per-entry skips and failures are data too.

The two single-entry roster-control routes are the exception. PATCH /b2b/roster/:rosterId and DELETE /b2b/roster/:rosterId write one row, so they have no partial-accept response to carry a reason and throw instead. See B2B Portal.

CodeStatusEnglish MessageArabic MessageCondition
ROSTER_ENTRY_NOT_FOUND404Roster entry not foundصف القائمة غير موجودNo roster entry with the given id on the caller's own company roster (also appears as a per-entry skip code on the batch link routes)
ROSTER_LINK_OPEN409This person has an open invitation — revoke it firstلدى هذا الشخص دعوة مفتوحة — يجب إلغاؤها أولاًA live, unexpired issued/sent/exported link still holds this seat, so the assignment cannot change and the person cannot be removed. Cleared with POST /b2b/roster/links/revoke.
ROSTER_SEAT_CONSUMED409This person already used their invitation — their seat is permanently theirsاستخدم هذا الشخص دعوته بالفعل — أصبح مقعده دائمًاThe beneficiary redeemed a link at some point. Redemption is permanent, even once that link is past its own expiry. The removal route also returns this code, with the message "This person already has activation history — their record cannot be removed", when the underlying account is no longer a bare staged end user.

Returned by POST /auth/magic-link on redemption. See Authentication.

CodeStatusEnglish MessageArabic MessageCondition
MAGIC_LINK_INVALID401This link is not validهذا الرابط غير صالحToken doesn't match any issued magic link
MAGIC_LINK_ALREADY_USED401This link has already been usedتم استخدام هذا الرابط بالفعلThe link's status is already used (or it lost the race to consume it)
MAGIC_LINK_REVOKED401This link has been revokedتم إلغاء هذا الرابطThe link was revoked before redemption
MAGIC_LINK_EXPIRED401This link has expiredانتهت صلاحية هذا الرابطThe link's 24h TTL has passed
MAGIC_LINK_USER_ALREADY_ACTIVE409This account already has an active SIMيوجد لدى هذا الحساب شريحة مفعّلة بالفعلRedemption succeeded but the user's latest activation is already activated. The link send/export routes pre-empt this at mint time with the per-entry skip LINK_USER_ALREADY_ACTIVE (same predicate), so a company-minted link should no longer reach this state

COMPANY_NOT_APPROVED (403) is also returned here — see Company Errors.


Document Errors (404 / 500)

Returned by GET /documents/:type/:entityId.pdf. See Documents.

CodeStatusEnglish MessageArabic MessageCondition
DOCUMENT_TYPE_NOT_FOUND404Document type not foundنوع المستند غير موجود:type isn't a registered document type
DOCUMENT_NOT_FOUND404Document not foundالمستند غير موجود:entityId isn't a valid UUID, or no matching entity exists
DOCUMENT_RENDER_FAILED500Failed to render documentفشل إنشاء المستندPDF rendering threw after the access policy and entity lookup both passed

Activation Errors (409 / 422)

CodeStatusEnglish MessageArabic MessageCondition
ACTIVATION_FAILED422Activation failedفشل التفعيلGeneral activation failure
ACTIVATION_ICCID_INVALID422ICCID validation failedفشل التحقق من رقم ICCIDOperator rejected ICCID
ACTIVATION_ESIM_DISABLED422eSIM activation is disabledتفعيل eSIM غير مفعّل حاليًاFEATURE_ESIM is off for an eSIM request, or a corporate B2B user attempted eSIM activation before that lane is enabled
ACTIVATION_CODE_INVALID422Invalid eSIM activation codeرمز تفعيل eSIM غير صالحeSIM activation create reached the operator validation path and the LPA activation code was rejected
ACTIVATION_ESIM_UNSUPPORTED_OPERATOR422This operator does not support eSIM activationهذا المشغل لا يدعم تفعيل eSIMsimType: esim was requested for an operator plugin that did not explicitly declare supportsEsim: true
ACTIVATION_PACKAGE_NOT_ON_CONTRACT409This package is not on your company's contractهذه الباقة غير مدرجة في عقد شركتكB2B activation: no roster entry, no assigned contract line, the requested package doesn't match the assigned line, or the contract is not active
ACTIVATION_LINK_NOT_REDEEMED409Open your company invite link before activatingيجب فتح رابط دعوة شركتك قبل التفعيلB2B activation: the roster entry has no redeemed invite link — OTP login alone cannot activate a staged seat
ACTIVATION_SEAT_ALREADY_USED409This account already has an active or pending SIMيوجد لدى هذا الحساب شريحة نشطة أو قيد التفعيل بالفعلB2B activation: the seat already has a pending/in-progress/activated SIM (failed/cancelled allow retry)
IDENTITY_ERROR422Identity verification failedفشل التحقق من الهويةIdentity verification initiation/retrieval failure

eSIM Store Errors (400 / 404 / 409 / 422 / 503)

Returned by the public eSIM store, store-order, admin catalog, admin order recovery, FX settings, and manual sync endpoints. See eSIM Store.

CodeStatusEnglish MessageArabic MessageCondition
STORE_DISABLED422eSIM store is disabledمتجر eSIM غير مفعّل حاليًاFEATURE_ESIM_STORE is off — gates browse (GET /store/destinations, GET /store/products, GET /store/products/:id) and store writes (POST /store/orders, POST /store/device-acks); GET /store/status stays public, and owned-order reads and the QR endpoint stay available so delivered codes are never locked out
STORE_PRODUCT_NOT_FOUND404Store product not foundمنتج المتجر غير موجودProduct is missing, or public detail hides it because it is inactive
STORE_PRODUCT_INACTIVE422Store product is inactiveمنتج المتجر غير متاح حاليًاBuy request targets an inactive product
STORE_CURRENCY_UNSUPPORTED400Unsupported store currencyعملة المتجر غير مدعومةCurrency value is outside the supported USD / SAR / AED / EUR / GBP / EGP set, or a supported currency's FX rate has not been fetched yet (details.currency + details.detail). On list and buy routes, unsupported currencies are rejected as standard validation errors; on the detail route, the explicit currency param fires this code
STORE_KYC_REQUIRED422This eSIM requires KYC and cannot be purchased yetتتطلب هذه الشريحة تحققًا من الهوية ولا يمكن شراؤها حاليًاBuy request targets a KYC provider SKU whose provider does not support the async verification flow (or is not registered). With a supporting provider the purchase proceeds and issuance answers with a verification URL instead
STORE_ORDER_NOT_FOUND404Store order not foundطلب المتجر غير موجودStore order is missing, foreign to the caller, or not issued yet for QR delivery; also returned by the admin order detail and requeue routes for unknown ids
STORE_SYNC_UNAVAILABLE503eSIM store sync is temporarily unavailableمزامنة متجر eSIM غير متاحة مؤقتًاManual admin catalog sync could not be enqueued because Redis/queueing is unavailable
STORE_ORDER_NOT_REQUEUEABLE409Store order is not in a requeueable stateطلب المتجر ليس في حالة تسمح بإعادة الإدراجAdmin requeue targeted an order that is not paid-without-an-issued-profile (already issued, completed, cancelled, or still pending payment)
STORE_REQUEUE_UNAVAILABLE503Store fulfillment requeue is temporarily unavailableإعادة إدراج تلبية طلب المتجر غير متاحة مؤقتًاAdmin requeue could not enqueue a store fulfillment job because Redis/queueing is unavailable
STORE_CHARGE_BELOW_MINIMUM422Charge amount is below the minimum allowed by payment processorsمبلغ الدفع أقل من الحد الأدنى المسموح به لمعالجات الدفعThe calculated store order charge amount is below the mandatory minimum threshold
STORE_PROVIDER_PAYMENT_EXTERNAL422External provider checkout is not supported yetالدفع عبر مزوّد الخدمة غير مدعوم بعدThe store order's provider has payment_mode = 'external'. Fail-closed — order creation and card/Apple Pay payment initiation both block before any insert or PSP call. Missing linkage or unrecognised mode values throw the same code.
STORE_PRICE_CHANGED409Store product price has changed; re-fetch the product and retry with the current priceتغيّر سعر منتج المتجر؛ يرجى إعادة جلب المنتج والمحاولة بالسعر الحاليOptional expectedPrice guard on POST /store/orders: the request carried expectedPrice and it was not strictly equal to the freshly computed presentment price.amount; details.currentPrice: { amount, currency } carries the current price so the client can re-render without a refetch
STORE_PROVIDER_NOT_FOUND404Store provider not foundمزوّد المتجر غير موجودAdmin provider toggle (PATCH /admin/store/providers/:id) targeted an id with no eSIM operator row — telecom operators are invisible to this route by design
STORE_PROVIDER_UNAVAILABLE422Store provider is temporarily unavailableمزوّد المتجر غير متاح مؤقتًاCheckout circuit breaker on POST /store/orders: the product's provider plugin is not registered in this process, its latest health reading is unhealthy, or the health check itself failed (fail closed)

Payment Errors (402 / 404)

CodeStatusEnglish MessageArabic MessageCondition
PAYMENT_INTENT_FAILED402Payment intent creation failedفشل إنشاء نية الدفعStripe intent error
PAYMENT_METHOD_NOT_SUPPORTED_FOR_ORDER422This payment method is not available for eSIM store ordersطريقة الدفع هذه غير متاحة لطلبات متجر الشرائح الإلكترونيةmada or STC Pay attempted on an eSIM store order; cards and Apple Pay are the only supported store rails
PAYMENT_APPLE_PAY_FAILED402Apple Pay payment failedفشل دفع Apple PayApple Pay confirmation failed
PAYMENT_STCPAY_FAILED402STC Pay initiation failedفشل بدء عملية STC PaySTC Pay initiation error
PAYMENT_RECEIPT_FAILED402Receipt retrieval failedفشل استرجاع الإيصالReceipt generation error
PAYMENT_ORDER_INVALID_STATUS402Order is not in pending_payment statusالطلب ليس في حالة انتظار الدفعThe order is not in pending_payment when a payment create call is attempted
PAYMENT_IDEMPOTENCY_CONFLICT402Idempotency conflictتعارض مفتاح الوحدةSame idempotency key with different parameters
PAYMENT_MISMATCH_RECORD_FAILED500Failed to record the payment mismatchفشل تسجيل عدم تطابق الدفعةWriting the reconciliation record and the failed-payment transition both failed on a mismatched webhook. Returned to the provider so it redelivers the event
ORDER_NOT_FOUND404Order not foundلم يتم العثور على الطلبThe payment request referenced an order that does not exist or is not owned by the caller

Idempotency conflict response:

json
{
  "error": {
    "code": "PAYMENT_IDEMPOTENCY_CONFLICT",
    "message": "A payment with this idempotency key already exists with different parameters",
    "details": {
      "existingPaymentId": "d5e6f7a8-b9c0-1234-defa-567890123456"
    }
  }
}

Operator Errors (502 / 504)

CodeStatusEnglish MessageArabic MessageCondition
OPERATOR_UNAVAILABLE502Operator API unavailableخدمات المشغل غير متاحةOperator API returned error
OPERATOR_TIMEOUT504Operator API timed outانتهت مهلة خدمات المشغلOperator API did not respond in time

Server Errors (5xx)

CodeStatusEnglish MessageCondition
INTERNAL_ERROR500An unexpected error occurredUnhandled server error
NOT_IMPLEMENTED501This endpoint is not yet implementedEndpoint stub (not yet built)

Rate Limiting (429)

When the rate limit (100 requests / 15 minutes / IP) is exceeded:

json
{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests, please try again later"
  }
}

Response headers include:

HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetWindow reset timestamp (Unix epoch)

Stripe Webhook Errors (400)

CodeStatusEnglish MessageArabic MessageCondition
STRIPE_WEBHOOK_SIGNATURE_MISSING400Stripe webhook signature header is missingرأس توقيع Stripe مفقودStripe-Signature header not provided
STRIPE_WEBHOOK_SIGNATURE_INVALID400Stripe webhook signature verification failedفشل التحقق من توقيع StripeSignature does not match payload

Reconciliation Codes

These codes are emitted as structured console.error records and are never returned as HTTP error responses. Some also write reconciliation records to the database:

CodeCondition
PAYMENT_PROVIDER_AMOUNT_MISMATCHProvider-reported payment intent amount, currency, or metadata does not match the persisted payment row. The payment is NOT completed, settlement is NOT enqueued, and the webhook still returns 200 (Stripe retry-storm prevention). A reconciliation record is written to the payment_webhook_events table with the mismatch detail, in the same transaction as the failed-payment transition. The structured log carries the paymentId, orderId, userId, expected vs received amounts and currencies, and the specific mismatched fields — no raw payload or client secret is logged. If that transaction fails, the webhook responds 500 PAYMENT_MISMATCH_RECORD_FAILED so the provider redelivers.

SIM Limits (CITC)

Per CITC regulations, users are limited by identity type:

Identity TypeMax SIMsidentityType Value
Citizen10citizen
Resident2resident
Visitor1visitor

Internal documentation - Activation System