Reference
Agent API reference
The API an embedded app or agent calls on a member's behalf, generated from its live OpenAPI document.
Generated from the live OpenAPI document at https://api.pylosystem.com/openapi/agent.json. It is the API an embedded app calls on behalf of a signed-in member; see Embedded apps.
Forms, drafts and display config, for agents and for web apps with PYLO behind them, and the agency API: plans, blueprints and connect links, on an agency token. PYLO is the source of truth: an embedded app keeps no sales data of its own.
Never put a workspace or agency token in a browser. Anyone using the page could take it and read the whole workspace, commission included, and PYLO refuses one presented from a web page (refused.token_in_browser). A web app signs its user in with PYLO (OAuth 2.1, authorization code with PKCE) and calls PYLO with that member's own session token, from an origin the workspace lists in Settings, Embedded apps.
| Route | Token | Scope |
|---|---|---|
| GET /api/v1/display | workspace | read |
| GET /api/v1/workspaces/{workspaceId}/display | workspace | read |
| GET /api/v1/me/board | workspace | read |
| GET /api/v1/workspaces | workspace | read |
| POST /api/v1/change-log | workspace | data:write |
| POST /api/v1/workspaces/{workspaceId}/change-log | workspace | data:write |
| POST /api/v1/forms/post-call | workspace | data:write |
| POST /api/v1/forms/past-call | workspace | data:write |
| POST /api/v1/forms/dm-close | workspace | data:write |
| POST /api/v1/forms/eod | workspace | data:write |
| POST /api/v1/forms/drafts | workspace | data:write |
| GET /api/v1/forms/drafts | workspace | read |
| GET /api/v1/agency/workspaces | agency | read |
| POST /api/v1/plans | agency | config:plan (Agency plan) |
| GET /api/v1/plans/{id} | agency | config:plan |
| POST /api/v1/plans/{id}/apply | agency | config:apply (Agency plan) |
| POST /api/v1/plans/{id}/request-approval | agency | config:plan |
| GET /api/v1/templates | agency | read |
| GET /api/v1/templates/{key} | agency | read |
| PUT /api/v1/templates/{key} | agency | config:plan (Agency plan) |
| POST /api/v1/workspaces/{id}/connect-links | agency | connect:links |
| GET /api/v1/workspaces/{id}/connect-links/{linkId} | agency | connect:links |
| POST /api/v1/workspaces/{id}/connect-links/{linkId}/revoke | agency | connect:links |
Base URL
https://api.pylosystem.com
Authentication
- pyloOAuth: oauth2. Sign in with PYLO. Authorization code with PKCE (S256), the resource parameter set to https://api.pylosystem.com/api/v1. Discovery: https://api.pylosystem.com/.well-known/oauth-authorization-server.
- bearer: HTTP bearer. A PYLO API token, for server-side agents only. Never put a workspace or agency token in a browser. Anyone using the page could take it and read the whole workspace, commission included, and PYLO refuses one presented from a web page (refused.token_in_browser). A web app signs its user in with PYLO (OAuth 2.1, authorization code with PKCE) and calls PYLO with that member's own session token, from an origin the workspace lists in Settings, Embedded apps.
- agencyBearer: HTTP bearer. A PYLO agency token (client_api_tokens with kind='agency', made on Agency OS, Tokens), for server-side agents only. It reaches the agency's plans, blueprints and connect links, and no workspace's data. Scopes: read, config:plan, config:apply, connect:links. Never put a workspace or agency token in a browser. Anyone using the page could take it and read the whole workspace, commission included, and PYLO refuses one presented from a web page (refused.token_in_browser). A web app signs its user in with PYLO (OAuth 2.1, authorization code with PKCE) and calls PYLO with that member's own session token, from an origin the workspace lists in Settings, Embedded apps.
Endpoints
GET /api/v1/display
Display config
The workspace's name, logo, colours, labels, modules to show, programmes and currency code, so one template app can brand itself for any workspace.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
GET /api/v1/workspaces/{workspaceId}/display
Display config, by workspace
The same, naming the workspace: the form a template app uses, and the one an agency token must use.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId | path | string | yes |
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
GET /api/v1/me/board
My board
The signed-in member's own board: the figures PYLO shows them on My Board. A closer's, setter's or SDR's token reads this and nothing workspace-wide. Needs a member's session token; an API token is refused with refused.drafts_only.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
GET /api/v1/workspaces
Workspaces
The workspaces this token reaches. An agency token names one in the path: /api/v1/workspaces/{id}/...
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
POST /api/v1/change-log
Record a change
A dated entry saying what changed and why: a price, an offer, a script, a rule. Written against the token's own workspace. Read it back with listChanges, and compare the figures either side with compareAroundChange.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
POST /api/v1/workspaces/{workspaceId}/change-log
Record a change, by workspace
The same, naming the workspace: the form an agency token must use, since it reaches more than one.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
workspaceId | path | string | yes | |
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
POST /api/v1/forms/post-call
File a post-call form
The app's own post-call form, with the app's own validation: the same errors, field by field. Filed as the signed-in member, on a call they hold a slot on. Idempotent on submission_id. Needs a member's session token; an API token is refused with refused.drafts_only.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
POST /api/v1/forms/past-call
Log a past call
A call that happened with no booking in PYLO, with its form. Idempotent on submission_id. Needs a member's session token; an API token is refused with refused.drafts_only.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
POST /api/v1/forms/dm-close
Log a DM close
A sale made over messages, with no call. Idempotent on submission_id. Needs a member's session token; an API token is refused with refused.drafts_only.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
POST /api/v1/forms/eod
File an end of day report
The member's own EOD. One per member per day: a second submission edits the first. Needs a member's session token; an API token is refused with refused.drafts_only.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
GET /api/v1/forms/drafts
Open drafts
Open drafts. A closer, setter or SDR sees their own.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
POST /api/v1/forms/drafts
Propose a draft
An agent proposes a form, for example a post-call form from a transcript, for a member to check and file. A draft never carries money: one with a cash, revenue, payment or instalment field is refused (refused.cash_figures). Idempotent on the Idempotency-Key header.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: insufficient_scope, refused.member_scope, refused.drafts_only, refused.cross_workspace, refused.token_in_browser, refused.origin |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
GET /api/v1/agency/workspaces
The agency's workspaces
Every workspace the agency holds and has not archived: id, name, slug, currency, status and when it was made, so an agent can name one in a plan or a connect link. Needs an agency token (client_api_tokens kind='agency') with read. A workspace token is refused with token.not_agency.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
POST /api/v1/plans
Draft a plan
Describe a workspace to create or change (settings, team, programmes, integrations to connect) and get back the plan: every change PYLO would make, what is blocked and why. Nothing is changed. Needs an agency token (client_api_tokens kind='agency') with config:plan, on the Agency plan or above. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 402 | tier.upgrade_required: the agency is not on the Agency plan or above |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
GET /api/v1/plans/{id}
A plan
A plan and its state: drafted, waiting for approval, approved, applied, or refused with the reason. Needs an agency token (client_api_tokens kind='agency') with config:plan. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
POST /api/v1/plans/{id}/apply
Apply a plan
Make the plan's changes. Idempotent on the Idempotency-Key header: a retry answers the first result. Without config:apply it is refused with requiredScope config:apply and approval "request": ask for approval instead. Tokens a plan issues for new members come back once, here. Needs an agency token (client_api_tokens kind='agency') with config:apply, on the Agency plan or above. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 402 | tier.upgrade_required: the agency is not on the Agency plan or above |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
POST /api/v1/plans/{id}/request-approval
Ask a person to approve a plan
For a token without config:apply. A person approves or declines the plan in the app. Needs an agency token (client_api_tokens kind='agency') with config:plan. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
GET /api/v1/templates
Blueprints
The agency's blueprints: saved workspace shapes a plan can start from. Needs an agency token (client_api_tokens kind='agency') with read. A workspace token is refused with token.not_agency.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
GET /api/v1/templates/{key}
A blueprint
One blueprint by its key. Needs an agency token (client_api_tokens kind='agency') with read. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
key | path | string | yes |
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
PUT /api/v1/templates/{key}
Save a blueprint
Create or replace a blueprint under its key. Needs an agency token (client_api_tokens kind='agency') with config:plan, on the Agency plan or above. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
key | path | string | yes | |
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 402 | tier.upgrade_required: the agency is not on the Agency plan or above |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
POST /api/v1/workspaces/{id}/connect-links
Make a connect link
A link a client opens to connect one integration to a workspace the agency holds, without an account. The response carries the link once. Needs an agency token (client_api_tokens kind='agency') with connect:links. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |
GET /api/v1/workspaces/{id}/connect-links/{linkId}
A connect link's state
When the link expires, whether it was revoked or completed, and each integration it offers with its state. Never the link itself or any credential. Needs an agency token (client_api_tokens kind='agency') with connect:links. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
linkId | path | string | yes |
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
POST /api/v1/workspaces/{id}/connect-links/{linkId}/revoke
Revoke a connect link
The link stops opening. A connection it already made stays. Needs an agency token (client_api_tokens kind='agency') with connect:links. A workspace token is refused with token.not_agency.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes | |
linkId | path | string | yes | |
Idempotency-Key | header | string | yes | A value of 8 to 200 characters, unique to this write. Send the same one when you retry: the first answer is returned again rather than the write being done twice. |
Request body: object.
| Response | Meaning |
|---|---|
| 200 | OK |
| 400 | Refused, with the field and the sentence: { error, field }. A write with no Idempotency-Key header is refused here with refused.idempotency_key_required. |
| 401 | No token, or not a PYLO token, or revoked |
| 403 | Refused with a machine readable reason: token.not_agency, scope.missing (with requiredScope) |
| 409 | A write with this Idempotency-Key is still running: refused.idempotency_in_progress |
| 422 | This Idempotency-Key was used for a different request: refused.idempotency_key_reused |