قواعد المراجعة

آخر تحديث: 2026-09-15

These guidelines list what an app has to meet to be listed in the marketplace. Every rejection and every change request cites at least one guideline number, so a vendor reads the basis of the decision instead of guessing it.

1. Security and data

1.1 Undeclared data is not carried

Your app may only send and accept the fields it declares in its manifest. A connection carrying an undeclared field goes outside what the user consented to.

1.2 Sensitive data is justified

Ports carrying identity, health, financial or biometric data are declared as such. A sensitive port with no written justification is rejected; the platform does not accept matches of this kind without a reason.

1.3 Your code does not run on the platform

Your app runs on your own infrastructure. The platform only calls the HTTPS endpoints you declare; you cannot send us code, scripts or packages to be executed.

1.4 Credentials are not reused

A token issued for one user cannot be used for another user, for another app, or for your own internal work.

1.5 No real personal data in media

Your screenshots and videos cannot show the name, email address, phone number, address, invoice or health data of your real customers. Use fictional sample data. The storefront is public, and a record that lands there has been published without that person's consent.

1.6 Records carry their private mark

Every record leaving a shared business object (`business/…`) port carries the `_private` field as a boolean, and it is `true` on records the user marked private. The mark is placed on a person: when a customer is marked private, the sales, appointment and payment records attached to them come out marked as well. A delivery that does not carry the mark is rejected on the platform side; an app that never computes the mark violates this guideline. You cannot choose NOT TO SEND a marked record: the platform does the cutting, you compute the mark and carry it. How the mark travels from a person to a record is written in guideline 1.10, and that is the mechanism this guideline rests on.

1.7 Fields are classified

Business object ports declare their fields inside `shape` and write the class of each field. Fields counted as the inside of a business (purchase price, cost, margin) are `internal`, and fields a person writes in their own words (note, description) are `free-text`; neither passes through a connection unless the user explicitly asks for it. The class in the dictionary is a FLOOR: a vendor may pull a field into a more closed class, never into a more open one. Because both ends are wired to a machine, a moderator does not need to know the dictionary by heart; a declaration more open than the dictionary drops the submission at the schema, and even if it does not drop, the dictionary's class is applied again at delivery.

1.8 Filtering applies on every surface data leaves the user through

*(2026-09-15, A17: half of this guideline WAS DROPPED. For a while the guideline also put filtering on the vendor for general ports with no schema; once measured, that half described a path the platform never cut, and it was closed. An output port carrying records must now declare a schema, and the platform does the cutting. The guideline below continues to hold on the vendor's OWN surfaces.)* Filtering private-marked records and fields in the `internal` / `free-text` classes applies not only on connections the platform builds, but on every surface data LEAVES the user through: read endpoints you open for add-ons, exports, and anything reachable with a key the user handed to a third party. The user's OWN screen is outside this and has to be: a person sees their own purchase price and their own note, and putting a filter there would mean hiding the user's data from the user. The distinction disappears silently in exactly one place: if the SAME identity resolver accepts both your panel session and the key you hand out, every panel endpoint turns into an externally reachable surface without anyone deciding so. The two identities are resolved separately, and a key issued to the outside never reaches panel endpoints.

1.9 Writes arriving from outside are validated as records

You cannot accept a write arriving from a connection or from an endpoint you opened yourself as it is. At least these three apply: data that will open a new record has to carry the field identifying that record (a name, for example); data that arrives without an identity and repeats the same record within a short window does not open a second record, it is answered with the identity of the existing one; there is a body limit rejected without being read. **The only exception to the identifying field requirement is a `business/party` record carrying the private mark:** that record is not a business record but an instruction about a person, and it carries no name because the platform reduces it to an identity (guideline 1.10). When a mark arrives for an identity you do not know, you store the mark but do not open a nameless record in the user's list. A rejected record does not drop the whole batch, it is reported one by one. The sender being authenticated does not remove this validation: the damage forms in the user's books, and a faulty integration dirties those books faster than an anonymous bot.

1.10 The party port carries the mark and applies an incoming mark

The private mark travels between apps together with the person's record, and the `business/party` port is the only way it travels. Both directions bind you. As the SENDER: when you mark a person, you do not pull them out of the port, you send the record with `_private: true`; the platform reduces it to an identity (`party_id` and the flag) and the name, phone number and address are not delivered. When the mark is lifted, the record goes in its normal form with `_private: false`. As the RECEIVER: when you receive a party record carrying `_private: true`, you have to mark YOUR OWN records attached to that identity; when `false` arrives, you remove the mark. An app that ignores an incoming mark silently voids a decision the user made in another app. **When a mark arrives for an identity you do not know:** you store the mark against that identity, but you do not open a nameless card in the user's list. The "identifying field" requirement of guideline 1.9 does not apply here, and it is written there too; until a name arrives there is no record to show, only a mark to remember.

1.11 A development identity cannot stay open in production

Your identity module may and should have a development branch: a fixed test user opened by an environment variable. But that branch has to be CLOSED in production, and what closes it must be code, not a document: if the app sees that variable while running in production, IT MUST NOT START. A test identity left open turns every panel endpoint into an unauthenticated surface; the whole of the user's books (internal fields, notes, key issuing, data deletion) opens to anyone who finds the address. The same requirement holds for every setting that bypasses authentication: a fixed token, a flag that turns verification off, a "public" test branch. The measure is one sentence: if this variable is carried into the production environment by accident, the app must fail to start.

1.12 A record carried in an opaque field is justified

The INSIDE of a field you declare as `json` or `binary` is unreadable for the platform: the user's private mark and the field classes can only be applied inside that field to a limited degree. So you declare every field you are able to declare; putting a whole record into a single opaque field means appearing to meet the requirement of guideline 1.1 while switching the cutting off. Opaque fields are NOT forbidden and will not be: in a relay the body passes through as it came from the source, in a polymorphic stream every event has a different body, and you cannot know the names of fields the user defined themselves either. During review these ports are flagged and you are asked why you could not declare the fields. Your answer is written into the submission thread; a submission leaving declarable fields opaque is asked for changes.

2. Technical requirements

2.1 The service has to be running

Every endpoint you declare must be callable. Your endpoints are probed during review, and an unreachable endpoint stops the review from finishing. There is NO continuous probing after publication: a dead endpoint is not noticed on its own, it is noticed by a user's connection breaking.

2.2 HTTPS is required

All endpoints are served over HTTPS with a valid certificate. Plain HTTP is not accepted.

2.3 The manifest matches the schema and the slug is permanent

The manifest has to match the published schema. Once approved, the slug does not change: users' installations, connections and the addresses they shared depend on it.

2.4 The app has to open inside the frame

Your app page opens inside the platform's frame. If your `X-Frame-Options` or `Content-Security-Policy` headers prevent this, the app cannot be used.

2.5 Access is given for review

An app that requires signing in provides, in its review information, the details of a demo account that does not expire. Without access the review can only be done on the manifest, and the app cannot be approved.

2.6 App or add-on is declared truthfully

The `listingKind` field in the manifest has to tell the truth. The measure is one sentence: is it useful with no connections at all? If it is, it is an app; if it is not, it is an add-on. Your declaration is tested during review by installing and opening it; a submission declaring a different kind than it actually is is asked for changes. An add-on has to have at least one input port: something that consumes nothing is attached to nothing.

2.7 An add-on does not connect to an add-on

There is always an app above an add-on. You can attach to more than one app, but you cannot build a chain; a connection joining two add-ons cannot be created. If you need to chain two capabilities, either combine them in a single add-on or apply as an app.

2.8 Embedded session rules are followed

When your app verifies an identity token it pins the algorithm, the issuer and the audience; it refuses a second session opened with the same **panel token** (replay rejection is a rule of the panel token, while a connection token arrives with the same `jti` on every delivery); it drops the token from the address bar as soon as the panel opens, and it sends `Referrer-Policy: no-referrer` on the panel page. These four are the only layer protecting the user's identity, and the platform cannot apply them on your behalf.

2.9 The dictionary is used for shared business objects

If the data you carry exists in the shared business object dictionary (party, product, stock level, stock movement, sales document, money movement, appointment, free time slot), you use that type and those field names. You are free to split more finely and to add fields that are not in the dictionary; you cannot give your own name to something shared. The gate is honesty: what your port returns has to be what you declared. How many ports you declare and how finely you split them is not a reason for rejection, it is a grade shown on your store page.

2.10 A declared input port accepts the probe call

During review every input port you declare is called once for real: the canonical example we would send on the wire for that port type arrives at your adapter with the `Authorization` header a normal delivery carries. The call carries the `x-kuratowski-test: true` header and the values inside it are fictional (`example.com`, `+1 555 01xx`); you do not have to process the record, you can see that header and drop it. If your adapter returns an error to this call the submission cannot be approved, because every connection a user would build would die with the same error. An endpoint that is unreachable or does not recognise our token is not rejected by this guideline; the only case rejected is an adapter that runs and refuses the type it declared itself.

3. Storefront content

3.1 The description has to be accurate

The name, description and screenshots describe the work the app actually does. Content describing a feature that does not exist is rejected.

3.2 No paid app is listed during the free period

There is no payment flow on the platform today. An app that charges the user through the platform cannot be listed.

3.3 Trademarks and copyright

You cannot use a trademark, logo, screenshot or text you do not own. You cannot choose a name evoking another product when you have no connection to it.

3.4 Placeholder content is not accepted

"Coming soon" screens, empty screenshots and sample text cannot go live. Storefront content has to be finished.

3.5 No steering to buy outside the storefront

The address of your vendor site is shown on your product page and is not removed; the user has to be able to see the company behind it. But your storefront text, your screenshots and your in-app screens cannot invite the user to buy the same app outside the platform, to sign up there, or to set it up there. The address you give is for information and support, not a second sales channel.

3.6 A privacy policy address is given

Your store page has to carry the `https` address of the privacy policy you publish yourself, and that address has to keep working. The text has to state clearly what data your app collects, how it collects it and what it uses it for. The user reads this BEFORE installing: installing means starting to pour their data into your system.

3.7 A support path stays open

Your store page carries a support address the user can reach you at, and that address is read. You, not the platform, are the first point of contact for a problem between a user and a vendor; a vendor who cannot be reached means the user has no option left but to uninstall the app.

3.8 Screenshots show the product running

Screenshots show the real screens of the app; they cannot be only a logo, a sign-in screen, a splash image or a marketing poster. If you provide a video, it too has to be a real recording of the product, not a promo film.

3.9 The category is chosen correctly

The category in the manifest has to describe the product's main job; a category chosen in order to sit in a more crowded bucket is corrected. The category says what work you do, not how you work.

3.10 Content is suitable for every age

The name, icon, screenshots, video and description have to be content a visitor of any age can see; the storefront is public and is browsed without signing in. Content praising violence, sexual content, hate speech or illegal activity is not listed.

3.11 Copies of the same product are not listed

Submitting the same product several times with small differences (a separate record per customer, per city or per colour) pollutes the catalogue and breaks discovery. If you offer different configurations to different customers, do it inside a single app.

3.12 Translations describe the same product

You can publish your store page in every language of the site. Every translation has to describe the same product, the same features and the same limits: a feature promised in one language and not promised in another is a false statement for the user who speaks that language. In a language you do not translate, your primary text is shown; a missing translation is not a violation, a WRONG translation is.

3.13 The primary text of a listing is written in English

You write your store page's main text (tagline and full description) in English, and you state which language you wrote it in. Translations are optional: add the languages you want and leave the rest empty. The reason is what the visitor sees: everyone without a matching translation reads the main text, so the main text has to be in the site's common language. A listing with no main text, or with main text that is not English, is sent to review. Leaving the full description empty in the main text while filling it in only for a translation has the same result: in that field, a visitor in another language sees nothing. When the tagline is empty the visitor reads your manifest's short description instead, so that sentence is judged as your listing's main text and it has to be English too.

4. Reviews and ratings

4.1 Rating manipulation is forbidden

You cannot offer incentives in exchange for a review or a rating, write ratings with fake accounts, or pressure a user into changing a negative review.

4.2 No personal data in replies

In the reply you write to a review you cannot share information about the user's account, email address or usage records.

5. Process

5.1 Every negative decision rests on a guideline

Every submission that is rejected or asked for changes carries at least one guideline number and a free-text reason. No decision is made without a number.

5.2 Resubmission

A submission that was asked for changes can be corrected and sent again. The review starts from the beginning.

5.3 Suspension

A published app can be suspended if it later turns out to violate one of these guidelines. The suspension is shown in the vendor console together with its reason.

5.4 A published page keeps being reviewed

Your store page goes live without waiting for review, but it is reviewed after publication: every change you make lands in the moderator's queue, and each language is read separately. Users can report an app as well. If a violation is found as a result of that review, guideline 5.3 is applied.

قواعد المراجعة