Integrations
Type | Base Path | Trigger Name |
---|---|---|
REST resource | ~{realm}/integrations/ | Not currently supported. |
RPC resource | oauth-token | N/A. |
This resource holds all published OAuth 2.0 integrations ("apps"), as well as your own integrations (even those not yet published). It's only possible to modify the integrations you have created yourself; all other integrations are read-only.
See OAuth Authorization Code Flow for more information about how to use OAuth 2.0 with Onslip 360.
Endpoints
Name | Method | Relative Path | Payload | Response | Description |
---|---|---|---|---|---|
addIntegration | POST | ~{realm}/integrations/ | Integration | Stored_Integration | Adds a new integration to the list. |
listIntegrations | GET | ~{realm}/integrations/ | N/A | Stored_Integration[] | Retrieves a list of integrations. |
getIntegration | GET | ~{realm}/integrations/{id} | N/A | Stored_Integration | Retrieves an integration. |
putIntegration | PUT | ~{realm}/integrations/{id} | Integration | Stored_Integration | Replaces an integration. |
updateIntegration | PATCH | ~{realm}/integrations/{id} | Partial_Integration | Stored_Integration | Updates specified integration fields. |
removeIntegration | DELETE | ~{realm}/integrations/{id} | N/A | N/A | Deletes an integration. |
requestOAuthAccessToken | POST | oauth-token | OAuthAuthorizationCodeRequest | OAuthAccessTokenResponse | The OAuth 2.0 Token Endpoint. |
The requestOAuthAccessToken
Endpoint
Once the user has authorized the integration and is redirected back
to your redirect_uri
endpoint, you should exchange the provided authorization code for an
AccessToken
using the requestOAuthAccessToken
endpoint. It's a standard OAuth 2.0 Token
Endpoint, except that
PKCE is mandatory.
Like all other endpoints, this endpoint negotiates Entity Format based on
the Accept
header. To fully comply with the OAuth 2.0 specification, unless you're not using one of our
SDKs, the response should be forced to application/json
by appending .json
to the endpoint URI,
like this: https://test.onslip360.com/v1/oauth-token.json
.
This endpoint is not scoped to a specific realm (since you don't know the realm of the user who authorized the
integration yet). Instead, you should use the realm
property in the response to determine what company alias to use
once the access token has been obtained.
If you use one of the SDKs we provide, you can use the oauthPKCE()
utility function to generate a
fresh code_challenge
/code_verifier
key pair.
Just submit an OAuthAuthorizationCodeRequest
payload and, if all goes
well, the server will respond with an OAuthAccessTokenResponse
response. You
will find the Hawk key ID in the access_token
property and the actual Hawk key value in the secret
property. The
company alias to use is provided in the realm
property; if a location was requested, you'll find its ID in the
location
property as well.
For integrations supporting external journals, the journal
property will contain the ID of the journal to use. To
bind/create an external journal as part of the authorization flow, the integration/client must request the
add-external-records
permission. Adding external-journal
to the features
list is optional but recommended if your
integration requires external journals.
Permissions
Permission | Description |
---|---|
edit-integrations | Client is allowed to add new integrations and to modify or delete existing integrations owned by this realm. |
show-integrations | Client is allowed to query the integration list and to fetch individual integrations. |
use-integrations | Client is allowed to activate/authorize a private or 3rd party integration. |
Entities
Interface Integration
namespace Integration {
export type Confinement = 'authorization' | 'location' | 'user';
export type Type = 'oauth';
}
interface Integration {
'alias': string;
'name': string;
'type': Integration.Type;
'name-t9n'?: Translation[];
'description'?: string;
'description-t9n'?: Translation[];
'icon'?: File;
'author': string;
'email': string;
'web-address': string;
'categories'?: StatusEvent.Category[];
'status-uri'?: string;
'permissions': Permission[];
'features': CompanyFeature.Flag[];
'confinements': Integration.Confinement[];
'oauth-redirect-uris': string[];
'id'?: number;
'created'?: DateTime;
'updated'?: DateTime;
'deleted'?: DateTime;
'updated-by'?: number;
'updated-from'?: number;
'tags'?: string[];
'labels'?: number[];
}
Property | Data Type | Description |
---|---|---|
alias | String | The integration alias (OAuth 2.0 client ID). Must be unique. |
name | String | The name of the integration. Must be unique. |
type | Integration.Type | Always set to oauth for now. |
name-t9n | Translation[]? | Translations of name . |
description | String? | A short description of the integration. |
description-t9n | Translation[]? | Translations of description . |
icon | FileArchive.File? | An icon/logo for the integration. |
author | String | The author of the integration. |
email | String | An email address where users can get information and support for the integration. |
web-address | String | A link to to a web page where users can get information and support for the integration. |
categories | StatusEvent.Category[]? | A set of categories the integration is applicable to. |
status-uri | URI? | An URI that accepts a POST :ed IntegrationStatusMessage and returns a SystemStatus payload in order to retrieve the integration's current status. |
permissions | Permission[] | A set of permissions the integration requires. |
features | CompanyFeature.Flag[] | A set of feature flags required by the integration. |
confinements | Integration.Confinement[] | A set of modifiers specifying how the AccessToken will be generated. See below. |
oauth-redirect-uris | URI[] | A set of OAuth 2.0 redirection endpoint URIs used by the integration. |
id | Int64? | The resource ID of this entity. |
created | DateTime? | Date and time when this entity was first created. |
updated | DateTime? | Date and time when this entity was last modified. |
deleted | DateTime? | Date and time when this entity was deleted. |
updated-by | Int64? | ID of User who last modified this entity. |
updated-from | Int64? | ID of Till (trusted device) which last modified this entity. |
labels | Int64[]? | A list of Label IDs associated with this entity. |
By specifying relevant categories
, your integration may be featured/checked in relevant sections in the Onslip 360
Backoffice.
To let the user know of problems or issues with your integration or its configuration, you can optionally provide a
status-uri
that accepts a POST
:ed IntegrationStatusMessage
and returns a
SystemStatus response.
The confinements
property determines how the resulting AccessToken
will be generated. It is
specified as a combination of the following flags.
Confinement | Description |
---|---|
authorization | A new access token will be generated for each authorization and previous authorizations, if any, will remain untouched. |
location | The access token will be bound to a specific location. |
user | The access token will be owned by the current user and is considered personal. |
If confinements
includes authorization
, any previously generated access token for this integration will remain
valid, and a new token will be created each time the integration is activated. The user will be asked to provide a name
for the token, so it's clear what the token is used for (like a particular mobile device, for instance).
If confinements
includes location
, the generated access token is scoped to a particular Location
by including the location ID in the token's alias
property. The user will be asked to specify what location should be
used as part of the authorization flow. Except for this, there are no special properties or restrictions associated with
the token.
If confinements
includes user
, the token will be belong to the user in question. If not present, on the other
hand, a service user will first be created, which will be the owner of the access token. This is appropriate if the
integration is not personal and should remain active even if the user who activated it is later removed.
If confinements
is empty, it means that a service user will be created, the token will not be bound to any location
and if any user re-authorizes the integration, the previous authorization will be revoked and replaced by the new one.
Interface IntegrationStatusMessage
This interface is somewhat similar to the WebHookMessage interface.
export interface IntegrationStatusMessage {
'service-endpoint-uri': string;
'company-alias': string;
'integration-alias': string;
'access-token'?: string;
}
Property | Data Type | Description |
---|---|---|
service-endpoint-uri | String | An API URI where the Onslip 360 server is available. Use this URI if you need to fetch more data or perform server operations as part of the web hook processing. |
company-alias | String | The realm from where the integration status is requested. |
integration-alias | String | The alias of the integration whose status is requested. |
access-token | String? | The Hawk ID of the integration's access token, if the integration is enabled and active. |
service-endpoint-uri
is provided so you can easily recognize what Onslip 360 environment (staging, production etc.)
the status request comes from. company-alias
(the customer realm/company alias) and integration-alias
(your Client
ID) might also be of interest to you, but it's the access-token
that, if provided, exactly specifies the integration
instance that should be checked. If set, it matches the access_token
property of the
OAuthAccessTokenResponse
message you received when the integration was
activated.
Finally, just like web hooks may be authenticated, these status request will also be Hawk-authenticated using the integration's access token (if there is one). This way you can ensure that it's actually Onslip 360 that is requesting the status check and not some malicious third party.
Interface SystemStatus
export interface SystemStatus {
'events': StatusEvent[];
}
Property | Data Type | Description |
---|---|---|
events | StatusEvent[] | A list of status events. |
Interface StatusEvent
export namespace StatusEvent {
export type Category = 'activation' | 'any' | 'accounting' | 'orders' | 'payments' | 'sales' | 'stock-balances';
}
export interface StatusEvent {
'log-level': TriggerAction.LogLevel;
'category': StatusEvent.Category;
'description'?: string;
'status-message': string;
'server-error'?: ServerError;
}
Property | Data Type | Description |
---|---|---|
log-level | TriggerAction.LogLevel | The log level of the event. |
category | StatusEvent.Category | The category of the event. |
description | String? | A description of the event. Used as a heading (overriding category) when displaying the event to the user. |
status-message | String | The event's status message. |
server-error | ServerError? | If the event is an error, additional error details. |
The events (and integrations) are organized using the following categories:
Category | Description |
---|---|
any | The event/integration is not related to any particular category. |
accounting | The event/integration is related to accounting/bookkeeping. |
activation | The event/integration is related to the activation of the integration or the generated access token. |
orders | The event/integration is related to orders. |
payments | The event/integration is related to payments, like custom payment methods and invoicing. |
sales | The event/integration is related to sales, like sales reports or other financial insights. |
stock-balances | The event/integration is related to stock balances. |
Status events reuse the log levels for triggers.
Log level | Description |
---|---|
errors | An error event. |
warnings | A warning event. |
results | An informational event. |
progress | Information about an operation currently in progress, like if the integration is currently syncing data and cannot report mismatches at this time. |
all | A debug event. |
Interface OAuthAuthorizationCodeRequest
interface OAuthAuthorizationCodeRequest {
'grant_type': string;
'client_id': string;
'redirect_uri': string;
'code': string;
'code_verifier': string;
}
Property | Data Type | Description |
---|---|---|
grant_type | String | Must be set to authorization_code . |
client_id | String | The alias (client ID) of the integration to activate. |
redirect_uri | String | The exact redirection endpoint URI used when authorization code was requested. |
code | String | The authorization code returned by the authorization code flow. |
code_verifier | String | The PKCE code verifier. |
Interface OAuthAccessTokenResponse
interface OAuthAccessTokenResponse {
'token_type': string;
'access_token': string;
'secret': string;
'algorithm': string;
'realm': string;
'scope'?: string;
'journal'?: number;
'location'?: number;
}
Property | Data Type | Description |
---|---|---|
token_type | String | Always Hawk . |
access_token | String | The Hawk key identifier. |
secret | String | The Hawk key secret (the raw value; not Base 64 -encoded). |
algorithm | String | Always sha256 . |
realm | String | The realm/company alias. |
scope | String? | If you were not granted all permissions you asked for, a space-separated list of permissions you did receive. |
journal | Int64? | If the token is bound to an external journal, the ID of the journal to use. |
location | Int64? | If the token is bound to a location (i.e., confinements includes location ), the ID of the location to use. |