Set the general-ledger mapping
The exports.gl_mapping.set operation: PUT /api/v1/exports/gl_mapping in the REST API and the exports_gl_mapping_set tool in the MCP server.
/api/v1/exports/gl_mappingReplaces the legal entity's general-ledger mapping in the mode of the request with the rules given (at most
200). Each rule maps Ownrecord ledger accounts to an account of the entity's own chart: account is an account
kind (processor_clearing, bank, tax_payable, revenue, processor_fees, …), an account code (e.g.
bank:ent_…:EUR) or a code prefix ending in * (e.g. tax_payable:EU_OSS_UNION:*); glAccount is the
general-ledger code and glName its name. Exports requested afterwards use the new mapping; earlier exports
keep theirs. Pass the version you read as expectedVersion to avoid overwriting someone else's change.
At a glance
- REST:
PUT /api/v1/exports/gl_mapping - MCP tool:
exports_gl_mapping_set - Operation ID:
exports.gl_mapping.set - Scope: Legal entity
- Permission:
ledger:write - Risk tier:
write - Dry run: Supported (send
Ownrecord-Dry-Run: true) - Idempotency:
Idempotency-Keyoptional - Modes: Test and live
- Authentication: API key with the
ledger:writescope - Since: M8
Request
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
rules | array of object | Yes | The whole table: it replaces the current rules. |
rules[].account | string | Yes | |
rules[].glAccount | string | Yes | |
rules[].glName | string | No | |
expectedVersion | integer (at least 0) | No | The mapping's version you read (0 while none is set): a guard against a concurrent change. |
Response
200 OK with a JSON object:
| Field | Type | Description |
|---|---|---|
object | "gl_mapping" | |
entityId | ent_… ID | |
livemode | boolean | |
rules | array of object | |
rules[].account | string | An account kind (e.g. tax_payable), an account code, or a code prefix ending in *. |
rules[].glAccount | string | The account in the entity's own chart of accounts. |
rules[].glName | string or null | |
version | integer | 0 while no mapping is set; pass it as expectedVersion when you change it. |
updatedAt | date-time or null | |
updatedBy | string or null |
Examples
Map clearing, bank, VAT, revenue and fees
PUT /api/v1/exports/gl_mapping
Authorization: Bearer or_test_…
Content-Type: application/json
{
"rules": [
{
"account": "processor_clearing",
"glAccount": "1360",
"glName": "Stripe clearing"
},
{
"account": "bank",
"glAccount": "1200",
"glName": "Bank"
},
{
"account": "tax_payable",
"glAccount": "1776",
"glName": "VAT payable"
},
{
"account": "tax_payable:EU_OSS_UNION:*",
"glAccount": "1777",
"glName": "OSS VAT payable"
},
{
"account": "revenue",
"glAccount": "8400",
"glName": "Revenue"
},
{
"account": "processor_fees",
"glAccount": "4970",
"glName": "Payment fees"
}
],
"expectedVersion": 2
}
Response (200):
{
"object": "gl_mapping",
"entityId": "ent_01m4tx5nj8emwbyf7y9vcf47zm",
"livemode": false,
"rules": [
{
"account": "processor_clearing",
"glAccount": "1360",
"glName": "Stripe clearing"
},
{
"account": "bank",
"glAccount": "1200",
"glName": "Bank"
},
{
"account": "tax_payable",
"glAccount": "1776",
"glName": "VAT payable"
},
{
"account": "tax_payable:EU_OSS_UNION:*",
"glAccount": "1777",
"glName": "OSS VAT payable"
},
{
"account": "revenue",
"glAccount": "8400",
"glName": "Revenue"
},
{
"account": "processor_fees",
"glAccount": "4970",
"glName": "Payment fees"
}
],
"version": 3,
"updatedAt": "2026-10-01T09:00:00.000Z",
"updatedBy": "usr_01m4tx5nj8emwbyf7y9vcf47zk"
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
validation_failed | 400 | A rule is malformed (a field missing or too long), or there are more than 200. | Fix the fields listed in details.issues and send the request again. |
gl_mapping_invalid | 400 | A rule's account isn't a kind, code or prefix, a glAccount isn't valid, or two rules map the same accounts (details.problems). | Fix the rules listed in details.problems (index, field, message): account is an account kind (e.g. tax_payable), an account code, or a code prefix ending in * (e.g. tax_payable:EU_OSS_UNION:*), each at most once; glAccount is 1–40 letters, digits, and ., -, _, / or spaces inside; at most 200 rules. |
version_conflict | 409 | The mapping changed since you read it (expectedVersion). | Fetch the object again and retry the change. |
idempotency_key_reused | 409 | The idempotency key was used before for another request. | Use a new Idempotency-Key for a different request, or resend the original request unchanged. |
scope_required | 400 | The request names no legal entity (an org key without Ownrecord-Entity, or a brand key: exports belong to the entity). | Call the operation with credentials or a target at its level: an organization, a legal entity, a brand or the platform (details.required_scope). |
permission_denied | 403 | You can't export this entity's books or change its mapping (ledger:write: finance, owners and admins). | Ask an organization owner or admin for a role or scope that allows this action. |
livemode_not_allowed | 403 | You have no live-mode access, so you can't use live exports. | Use test mode, or credentials for the target's mode. Developers need live access granted by an organization owner or admin. |
It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, resource_not_found, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.