# List your app for every organization

> For partners. Register an app, accept the Partner and App Terms, apply for listing with your publisher identity, privacy policy, security questionnaire and scope justifications, and keep the listing as your app changes.

A **listed app** can be installed by any organization on Ownrecord, and its consent screen shows a **verified publisher**. Ownrecord reviews every listed app before other organizations can install it. A private app needs no review: it installs only in the organization that registered it.

This guide is for partners: accounting firms, agent builders and other companies whose app acts on many organizations' data. The [agents and apps](https://ownrecord.io/docs/concepts/agents-and-apps.md#apps) page explains how installed apps act.

## 1. Register the app

Register the app under **Organization → Agents & apps → Your apps (Developers → Apps)**, or with [`apps.create`](https://ownrecord.io/docs/reference/apps-create.md). Tick **List it for every organization** (`visibility: "listed"`), or leave it private and list it later.

`scopes` are the most the app may ask for. Ask only for what your service needs: every scope needs a justification in your application, and financial, compliance and security scopes get the closest look.

Until the listing is approved, the app works as a private app: your own organization can install it to test it, other organizations can't.

## 2. Accept the Partner and App Terms

An owner or admin of your organization reads the [Partner and App Terms](https://ownrecord.io/legal/partners) and accepts them on the app's page, or with [`partner_terms.accept`](https://ownrecord.io/docs/reference/partner-terms-accept.md). They cover data use within the granted scopes, security, incident notification, branding, review and delisting, and liability.

Acceptance is recorded for your organization with the version and an [audit log](https://ownrecord.io/docs/concepts/audit-log.md) entry, like the Terms of Service. A person signed in to the console accepts; API keys, agents and apps can't. When a **material** new version takes effect, your organization accepts it again before its next application; [`partner_terms.get`](https://ownrecord.io/docs/reference/partner-terms-get.md) says `acceptance_required` until then. An announced version can be accepted ahead of time.

## 3. Prepare the application

Open the app's page (the app's name under **Your apps**). The application asks for:

| Part                   | What Ownrecord checks                                                                                                    |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Publisher              | Your registered legal name, country and website belong to a real company. A contact who reads Ownrecord's emails.        |
| Privacy policy         | It's reachable, names you, and says what the app does with organizations' data.                                          |
| Security questionnaire | Where data is stored, encryption, credential storage, staff access, incident response, sub-processors, model training, … |
| Scope justifications   | Each scope is needed for the service, and no broader than it.                                                            |

The questionnaire's questions and its version come with [`apps.listing.get`](https://ownrecord.io/docs/reference/apps-listing-get.md). Some answers ask for details: for example a "Yes" to sharing data with sub-processors asks you to name them.

> **Proposed criteria:** The review criteria and the questionnaire are a proposal still to be confirmed before launch. Answers are
> stored with the questionnaire version they answer, so a later version doesn't change what you submitted.

## 4. Submit it

**Submit for review** on the app's page, or call [`apps.listing.submit`](https://ownrecord.io/docs/reference/apps-listing-submit.md). The example is shortened: a real application answers every required question and justifies every scope.

```bash
curl -s https://ownrecord.io/api/v1/apps/ocl_01m4ttwd3veh9apbewxheq5xha/listing \
  -H "Authorization: Bearer $ORG_MANAGEMENT_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "publisher": {
      "legalName": "Ledgerly AI B.V.",
      "country": "NL",
      "websiteUrl": "https://ledgerly.example",
      "contact": { "name": "Mira de Vries", "email": "partners@ledgerly.example" }
    },
    "privacyPolicyUrl": "https://ledgerly.example/privacy",
    "questionnaire": { "version": 1, "answers": [
      { "questionId": "data_location", "details": "AWS eu-central-1, Germany" },
      { "questionId": "encryption_at_rest", "answer": "yes" }
    ] },
    "scopeJustifications": [
      { "scope": "filings:read", "justification": "Reads filing periods to prepare each return." }
    ]
  }'
```

An incomplete application is refused with [`app_listing_incomplete`](https://ownrecord.io/docs/reference/errors.md#app_listing_incomplete); `details.problems` lists each missing answer or justification. Without a current acceptance of the terms it's [`partner_terms_not_accepted`](https://ownrecord.io/docs/reference/errors.md#partner_terms_not_accepted).

## 5. The review

The listing's `status` moves as Ownrecord reviews it:

| Status              | Meaning                                                                              | What you do                                                                          |
| ------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------ |
| `not_submitted`     | No application yet, or you withdrew it                                               | Submit it                                                                            |
| `pending`           | Ownrecord reviews it. You can still change it: submitting again replaces it          | Wait, or [withdraw](https://ownrecord.io/docs/reference/apps-listing-withdraw.md) it |
| `changes_requested` | The reviewer needs changes; their note says which                                    | Change the application and submit it again                                           |
| `approved`          | Listed: any organization can install the app, with a verified publisher              | Nothing                                                                              |
| `rejected`          | Not listed; the note says why. Your own organization can still use the app privately | Change what the note says, and submit again                                          |

Each decision comes with a note from the reviewer. Your contact gets it by email, the app's page shows it, and your organization's [event feed](https://ownrecord.io/docs/concepts/events.md) gets an `app.listing_approved`, `app.listing_changes_requested` or `app.listing_rejected` event. The reviewer's name is never shown.

## 6. Keep the listing as your app changes

- **New scopes.** If an approved app asks for more scopes ([`apps.update`](https://ownrecord.io/docs/reference/apps-update.md)), they go back to review (`pending`). The app stays listed for its approved scopes: other organizations can consent only to those, and installations keep what they consented to. Once the new scopes are approved, organizations add them by consenting again. Justify each new scope by submitting the application again (or withdraw the review to stay with the approved scopes).
- **Fewer scopes** apply at once and need no review. A scope you remove and add back is reviewed again.
- **A new name or publisher**, or a new legal name, country or website in the application, is reviewed before the app shows as a verified publisher again. Until then other organizations can't install it.
- **Making the app private** ends the listing. Organizations that installed it keep their installations until they remove them.
- **A rejection** ends the listing in the same way.

## 7. Agents your app owns

An installed app can ask for an **agent it owns** in an organization, for work that runs without a user's session, such as filing. Call [`app_installations.create_agent`](https://ownrecord.io/docs/reference/app-installations-create-agent.md) with the app's own access token and your installation's ID, a role and scope, and the agent's public keys. It's a security operation, so the call always answers with an approval request; an owner or admin of the organization (not the person who installed your app) approves it in the console, and the agent is then created exactly as asked. Its `resultRef` is the agent's ID; the agent signs in with `private_key_jwt` using your private key. The agent never gets more than your installation was granted, works in test mode unless live mode was asked for and the installer has it, and stops when your app is paused or uninstalled.

## 8. If Ownrecord suspends your app

When an app is compromised (a leaked secret or key, tokens used from unknown networks) or breaks the Partner and App Terms, Ownrecord can suspend it in every organization at once. Every token, code and grant it holds is revoked, every installation is paused (`pausedReason: platform_suspended`), the agents it owns stop, and the OAuth server issues it nothing until the suspension ends: token requests fail with `invalid_client`, and nobody can install it or resume an installation ([`app_suspended`](https://ownrecord.io/docs/reference/errors.md#app_suspended)). Your organization and every organization that installed the app get an `app.suspended` event and an email with the reason; the app's page shows it.

Fix what the reason says (rotate the secret with [`apps.rotate_secret`](https://ownrecord.io/docs/reference/apps-rotate-secret.md), for example) and contact Ownrecord support. Once Ownrecord reinstates the app (`app.reinstated`), it can be authorized and installed again, but **no installation resumes by itself**: each organization decides and resumes its own, and your app then asks it for authorization again.
