> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dualentry.com/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Give an Integration Access to DualEntry

> Create a scoped API key in Organization Settings, choose the roles it carries, and hand it to the developer or vendor who needs it.

This guide shows you how to grant an application, script, or vendor programmatic access to your organization's DualEntry data by issuing it an API key.

You need the **Admin** role. The Developer access tab is disabled for every other role, including Controller, and the underlying endpoints reject non-admins. If you do not have it, send this page to someone who does, along with the list of operations your integration performs.

## Decide the roles first

The key carries roles of its own, and it can do exactly what those roles permit. The key is not tied to the person who created it and does not inherit anyone's permissions. Match the roles to what the integration actually does, before you open the dialog:

| What the integration does                                  | Role to assign          |
| ---------------------------------------------------------- | ----------------------- |
| Reads records or pulls reports                             | **View-Only**           |
| Creates or edits bills, vendor payments, purchase orders   | **Accounts Payable**    |
| Creates or edits invoices, customer payments, sales orders | **Accounts Receivable** |
| Creates journal entries or bank transfers                  | **Accountant**          |
| Edits existing records across the ledger but creates none  | **Controller**          |
| Manages users, integrations, or tenant configuration       | **Admin**               |

Two of these are narrower than their names suggest, and both catch people out. **Accountant** creates journal entries and bank transfers but is read-only on bills and invoices. **Controller** can edit every record type and creates none. An integration that posts bills needs Accounts Payable, not Accountant, and an integration that creates anything at all needs a role that grants `create` on that record type.

A key can hold several roles, so an integration spanning AP and AR takes both. If no combination fits, clone the closest role and adjust it; custom roles appear in this picker alongside the system ones.

Reach for **Admin** only when nothing narrower works. A key holding Admin bypasses permission checks entirely rather than being granted a permission set, so it is exempt from every restriction above.

For the full matrix, see [User roles and permissions](/accountants/platform-configuration/user-roles-and-permissions#permission-matrix).

The picker is optional and nothing is selected by default, but a key with no roles is useless: it authenticates and then fails every permission-guarded endpoint with `403`. Always select at least one role.

Issue one key per integration. Sharing a key between two systems means you cannot revoke one without breaking the other.

## Issue the key

<Steps>
  <Step title="Open the API Keys tab">
    Go to **Settings → Organization → Developer access → API Keys**.
  </Step>

  <Step title="Open the create dialog">
    Select the **+** button in the header row of the key table.
  </Step>

  <Step title="Name it after the integration">
    Enter an **API Key Name** such as `netsuite-migration` or `billing-service-prod`. The name is the only label you will have when you come back to revoke it, so avoid `test`. Names must be unique within the organization; reusing one returns `Label already exists`.
  </Step>

  <Step title="Select the roles you decided on">
    Open the **Roles** dropdown and select the roles. The field takes more than one.
  </Step>

  <Step title="Create and copy">
    Select **Create API Key**, then copy the full key from the dialog before closing it. It is displayed once and cannot be retrieved afterward. If you lose it here, revoke the key and issue another.
  </Step>
</Steps>

## Hand it over

Send the key through your password manager's sharing feature or another channel that expires. Do not paste it into Slack, email, or a ticket. A key in a chat history is a key in your organization's search index, readable by anyone who joins the channel later.

Tell the recipient which environment the key is for. Keys are specific to the environment they were created in, and the environment is baked into the key's prefix, so a production key will not authenticate against development. If they need a development key as well, issue it from your organization in that environment and note which is which.

Tell them the roles you assigned, too. A developer who knows the key is scoped to View-Only will recognize a `403` on a write as expected behavior rather than a broken credential, and will come back for the right scope instead of debugging their HTTP client.

Once the key is delivered, record which integration holds it somewhere your team will look during an incident. The key table shows the name you chose and nothing about who received it.

## Confirm it is working, then keep an eye on it

Ask the recipient to make one call. The **Last Used** column on the key row fills in once a request authenticates successfully. It shows a date rather than a timestamp, and the underlying value is written asynchronously and only refreshed once a minute, so do not expect it to move the instant a call lands.

Review the table periodically and revoke any key whose **Last Used** date has gone stale, or whose integration has been retired. To revoke, select the **⋮** menu on the key's row and choose **Revoke API Key**. There is no confirmation prompt: the key stops working immediately, and a revoked key cannot be reactivated.

If an integration's needs change, you do not have to reissue. The same **⋮** menu has an **Edit** action that changes the key's name and roles in place, leaving the secret intact.

## If something goes wrong

**The create dialog rejects the name.** `Label already exists` means another key in the organization already uses it, including a revoked one. Revoked keys keep their names, so add a date or a version to distinguish the new one.

**You closed the dialog without copying the secret.** It cannot be retrieved. Revoke the key and create another; nothing else in the product will show you that value again.

**The Developer access tab is greyed out.** You do not hold the Admin role. No other role can open it, and there is no read-only view of the key table for Controller or anyone else.

**The recipient reports `403` on every call.** Check the Roles column on the key's row. An empty Roles cell means the key was created without roles, which authenticates but is refused everywhere. Use **Edit** on the row to add them; the secret keeps working.

**Last Used stays empty after a successful call.** The value is written asynchronously and debounced by a minute, and the column shows a date rather than a time. Reload after a minute before concluding the key is unused.

## Next steps

* [How to Authenticate Your Requests to the DualEntry API](./how-to-authenticate-your-requests) for what the recipient does with the key
* [How to Replace an API Key](./how-to-replace-an-api-key) for rotation and leaked keys
* [Authentication](./authentication) for the header specification and error responses
