Connect a payment processor
The processor_connections.create operation: POST /api/v1/processor_connections in the REST API and the processor_connections_create tool in the MCP server.
/api/v1/processor_connectionsConnects a payment processor account to the legal entity of the request, in the request's mode. Ownrecord tests the key at the processor, stores it encrypted (it is never shown again), and sets up the webhook endpoint the processor sends payment events to.
- Stripe (
processor: "stripe"): a restricted key (rk_live_…; test mode also takesrk_test_…orsk_test_…) with write access to PaymentIntents, SetupIntents, PaymentMethods, Customers, Refunds, Disputes and Webhook Endpoints and read access to Balance and Payouts, plus the account's publishable key (pk_…). A key missing permissions is refused withprocessor_permissions_missinglisting them. Ownrecord creates the webhook endpoint on the account itself; on a development machine (no public URL) pass the signing secret ofstripe listen --print-secretaswebhookSecretinstead and forward events with the Stripe CLI. - Mollie (
processor: "mollie"): an API key of the request's mode (live_…ortest_…, from Mollie's dashboard → Developers → API keys), bound to one website profile; or an organization access token (access_…) withprofileId(pfl_…), which reconciliation of Mollie's balance transactions needs (an API key is accepted and reportsbalances.readas missing). Checkout redirects buyers to Mollie's payment page, which offers the methods enabled on the profile (cards, iDEAL, Bancontact, SEPA Direct Debit for renewals, …). Mollie needs no webhook setup: every payment Ownrecord creates carries this connection's webhook URL. - Fake (
processor: "fake"): the development and CI processor, only where development access is on. The key is optional.
Brands then use the connection for checkout (spec §15.4; processor_connections.routing.update sets a brand's
primary and secondary). Needs a sign-in within the last 15 minutes in the console; security tier for agents.
At a glance
- REST:
POST /api/v1/processor_connections - MCP tool:
processor_connections_create - Operation ID:
processor_connections.create - Scope: Legal entity
- Permission:
processors:admin - Risk tier:
security - Dry run: Not supported
- Idempotency:
Idempotency-Keyrequired - Modes: Test and live
- Authentication: API key with the
processors:adminscope - Fresh sign-in: In the console, a sign-in within the last 15 minutes
- Since: M4
Request
Body
A JSON object (Content-Type: application/json):
| Field | Type | Required | Description |
|---|---|---|---|
processor | one of stripe, mollie, fake | Yes | |
label | string | No | |
apiKey | string | No | |
publishableKey | string | No | |
webhookSecret | string | No | |
profileId | string | No |
Response
201 Created with a JSON object:
| Field | Type | Description |
|---|---|---|
id | pcon_… ID | |
object | "processor_connection" | |
entityId | ent_… ID | |
livemode | boolean | |
processor | one of stripe, mollie, fake | |
label | string | |
status | one of active, degraded, disconnected | |
statusReason | string or null | |
accountId | string or null | |
keyHint | string | |
publishableKey | string or null | |
checkoutComponent | one of stripe_payment_element, redirect, fake | |
webhook | object | |
webhook.mode | one of managed, manual | |
webhook.url | string | |
webhook.endpointId | string or null | |
webhook.lastEventAt | date-time or null | |
lastTest | object | |
lastTest.ok | boolean | |
lastTest.missingPermissions | array of string | |
lastTest.message | string or null | |
lastTest.checkedAt | date-time | |
failures | object or null | |
disconnectedAt | date-time or null | |
createdAt | date-time | |
updatedAt | date-time | |
version | integer (at least 1) |
Examples
Connect Stripe in test mode
POST /api/v1/processor_connections
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json
{
"processor": "stripe",
"apiKey": "rk_test_ExampleOnlyNotARealKey000000000AbCd",
"publishableKey": "pk_test_ExampleOnlyNotARealKey000000000AbCd"
}
Response (201):
{
"id": "pcon_01m4vyt4mxe0s9zzk90373z6p6",
"object": "processor_connection",
"entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
"livemode": false,
"processor": "stripe",
"label": "Stripe",
"status": "active",
"statusReason": null,
"accountId": "acct_1ExampleAccount01",
"keyHint": "rk_test_…AbCd",
"publishableKey": "pk_test_ExampleOnlyNotARealKey000000000AbCd",
"checkoutComponent": "stripe_payment_element",
"webhook": {
"mode": "managed",
"url": "https://ownrecord.io/api/webhooks/stripe/pcon_01m4vyt4mxe0s9zzk90373z6p6",
"endpointId": "we_1ExampleEndpoint01",
"lastEventAt": null
},
"lastTest": {
"ok": true,
"missingPermissions": [],
"message": null,
"checkedAt": "2026-10-14T12:00:00.000Z"
},
"failures": null,
"disconnectedAt": null,
"createdAt": "2026-10-14T12:00:00.000Z",
"updatedAt": "2026-10-14T12:00:00.000Z",
"version": 1
}
Connect Mollie in test mode with an API key
POST /api/v1/processor_connections
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json
{
"processor": "mollie",
"apiKey": "test_ExampleOnlyNotARealMollieKey0AbCd"
}
Response (201):
{
"id": "pcon_01m4vyt4mxe0s9zzk90373z6p9",
"object": "processor_connection",
"entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
"livemode": false,
"processor": "mollie",
"label": "Mollie",
"status": "active",
"statusReason": null,
"accountId": "pfl_ExampleProf1",
"keyHint": "test_…AbCd",
"publishableKey": null,
"checkoutComponent": "redirect",
"webhook": {
"mode": "managed",
"url": "https://ownrecord.io/api/webhooks/mollie/pcon_01m4vyt4mxe0s9zzk90373z6p9",
"endpointId": "mollie_payment_webhooks_0123456789abcdef01234567",
"lastEventAt": null
},
"lastTest": {
"ok": true,
"missingPermissions": ["balances.read"],
"message": "Connected with an API key. Reconciliation of Mollie balance transactions needs an organization access token (access_…) with balances.read.",
"checkedAt": "2026-10-14T12:00:00.000Z"
},
"failures": null,
"disconnectedAt": null,
"createdAt": "2026-10-14T12:00:00.000Z",
"updatedAt": "2026-10-14T12:00:00.000Z",
"version": 1
}
Use the fake processor in development
POST /api/v1/processor_connections
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json
{
"processor": "fake"
}
Response (201):
{
"id": "pcon_01m4vyt4mxe0s9zzk90373z6p7",
"object": "processor_connection",
"entityId": "ent_01m4ttwd3veh9apbewxheq5xh4",
"livemode": false,
"processor": "fake",
"label": "Fake processor",
"status": "active",
"statusReason": null,
"accountId": "acct_fake_0123456789abcdef",
"keyHint": "fake_…9f2c",
"publishableKey": null,
"checkoutComponent": "fake",
"webhook": {
"mode": "managed",
"url": "http://localhost:3000/api/webhooks/fake/pcon_01m4vyt4mxe0s9zzk90373z6p7",
"endpointId": "we_fake_0123456789abcdef01234567",
"lastEventAt": null
},
"lastTest": {
"ok": true,
"missingPermissions": [],
"message": null,
"checkedAt": "2026-10-14T12:00:00.000Z"
},
"failures": null,
"disconnectedAt": null,
"createdAt": "2026-10-14T12:00:00.000Z",
"updatedAt": "2026-10-14T12:00:00.000Z",
"version": 1
}
Errors
| Code | HTTP status | When | What to do |
|---|---|---|---|
validation_failed | 400 | A key is missing or isn't shaped like the processor's keys, or a field doesn't apply to the processor. | Fix the fields listed in details.issues and send the request again. |
processor_not_available | 400 | The fake processor outside development. | Connect Stripe or Mollie. The fake processor exists only in development and test. |
processor_key_mode_mismatch | 400 | A key belongs to the other mode. | Use a test key (Stripe rktest…, Mollie test*…) for a test-mode connection and a live key (rk_live*…, live_…) for a live-mode connection, or switch the console's mode. |
processor_key_not_restricted | 400 | A live connection with the account's secret key (sklive…). | Create a restricted key (rklive…) with the permissions listed in the docs instead of using the account's secret key (sklive…). |
processor_credentials_invalid | 400 | The processor rejected the key. | Copy the key again from the processor's dashboard (Stripe: Developers → API keys). It may have been rolled or deleted. |
processor_permissions_missing | 400 | The restricted key lacks permissions (details.missing_permissions). | Edit the restricted key in the processor's dashboard and grant the permissions listed in details.missing_permissions, then try again. |
processor_webhook_url_not_public | 400 | Stripe can't reach this deployment; pass webhookSecret. | On a development machine, run stripe listen --print-secret, pass the secret it prints (whsec_…) as webhookSecret, then forward events with stripe listen --forward-to the connection's webhook URL. |
processor_account_already_connected | 409 | The account is already connected to the entity in this mode. | Rotate the key of the existing connection (processor_connections.update) instead of connecting again. |
processor_request_failed | 502 | The processor couldn't be reached or refused the request. | If retryable is true, retry with the same Idempotency-Key after a short wait; otherwise check details.code. |
upstream_timeout | 502 | The processor didn't answer in time. | Retry the request with the same Idempotency-Key after a short wait. |
scope_required | 400 | The request names no legal 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 manage processor connections here. | Ask an organization owner or admin for a role or scope that allows this action. |
fresh_auth_required | 403 | Your last sign-in is older than 15 minutes. | Sign in again, then repeat the action within 15 minutes. |
It can also return these common errors: api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, resource_not_found, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, dry_run_not_supported, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.