---
url: /build-your-integration.md
---
# Build your integration

The [Quickstart](/quickstart) uses raw `curl` for a proof of concept. The production integration guides use the [backend SDK](#the-sdk-does-the-boring-parts).

Follow these chapters in order:

| Chapter | What you'll do |
|---|---|
| **[Create a checkout](/create-checkout)** | Turn a cart into a `checkout_url` for the customer |
| **[Webhooks](/webhooks)** | Receive and verify authorization events |
| **[Capture & checkout status](/capture-and-status)** | Capture the payment and read checkout state for reconciliation |

To manage the front-end launch, use the [Maytes Checkout Button](/checkout-button). It opens the Maytes checkout in a popup on wide screens and in the same tab on phones.

Already taking payments with **Stripe**? Put the button straight into your [express row](/stripe-express-checkout), or offer Split with Maytes as a custom payment method in your [Payment Element](/stripe). The three chapters above still apply — only the front-end launch differs.

## Use the SDK

Maytes provides official **server-to-server SDKs** for **TypeScript, Python, PHP, Go, Java, Ruby, and .NET**. All SDKs are generated from one API definition, expose the same operations, and stay aligned with the API. Examples are available in all seven languages.

Use the SDK **only on your backend**. Keep `client_id`, `client_secret`, and the webhook signing secret server-side; never put them in browser code. Get credentials from the [merchant portal](/portal) after completing [Onboarding](/onboarding).

### Install it

::: tip One language, whole site
Pick your language in any code block below and every example on every page
switches to it, including next time you visit.
:::

::: code-group

```bash [TypeScript]
npm install @maytes/api-client-js
# or: pnpm add @maytes/api-client-js · yarn add @maytes/api-client-js
```

```bash [Python]
pip install maytes-api-client-py
```

```bash [PHP]
composer require maytes/api-client-php
```

```bash [Go]
go get github.com/kttipay/maytes-api-client-go
```

```bash [Java]
# Not on Maven Central yet. Build from source:
git clone https://github.com/kttipay/maytes-api-client-java
cd maytes-api-client-java && mvn install
```

```bash [Ruby]
gem install maytes-api-client-rb
# or in a Gemfile:  gem 'maytes-api-client-rb'
```

```bash [.NET]
dotnet add package maytes-api-client-net
```

:::

### The SDK does the boring parts

* **Authentication is automatic.** Construct the client once with your credentials. On first use, the SDK mints and caches an access token. After a `401`, it refreshes the token and retries automatically. You do not call `/oauth/token`; [Authentication](/authentication) explains the underlying flow.
* **Webhook verification takes one call.** The SDK authenticates signed deliveries and returns the parsed event. See [Verify the signature](/webhooks#verify-the-signature).
* **Requests and responses are typed.** Amounts remain integers, and timestamps parse to the language's date type.

### What it covers

| Operation | Chapter |
|---|---|
| `CreateCheckout` | [Create a checkout](/create-checkout) |
| `GetCheckout` | [Reading the checkout status](/capture-and-status#reading-the-checkout-status) |
| `CaptureCheckout` | [Implement capture](/capture-and-status#implement-capture) |
| `CancelCheckout` | [If you can't fulfill the order](/capture-and-status#if-you-can-t-fulfill-the-order) |
| `RefundCheckout` | [Refunds](/refunds) |
| `GetHealth` | Liveness probe |
| `verifyWebhookSignature` | [Verify the signature](/webhooks#verify-the-signature) — authenticates an inbound delivery without making an API call |

::: warning Not in the SDK
The SDK does not currently manage [webhook subscriptions](/webhooks#managing-your-subscription). Use the portal or call the subscription endpoints with raw HTTP and the same Bearer token.
:::

## Construct the client

Construct the client **once at startup**, not once per request. Recreating it discards the cached access token and mints a new token for every call.

::: code-group

```ts [TypeScript]
import { createMaytesApiClient } from '@maytes/api-client-js';

export const maytes = createMaytesApiClient({
  endpoint: 'https://api.maytes.co',
  clientId: process.env.MAYTES_CLIENT_ID!,
  clientSecret: process.env.MAYTES_CLIENT_SECRET!,
});
```

```python [Python]
from maytes_api_client import create_maytes_api_client

maytes = create_maytes_api_client(
    "https://api.maytes.co",
    client_id=os.environ["MAYTES_CLIENT_ID"],
    client_secret=os.environ["MAYTES_CLIENT_SECRET"],
)
```

```php [PHP]
use MaytesApiClient\ClientFactory;

$maytes = ClientFactory::create(
    'https://api.maytes.co',
    getenv('MAYTES_CLIENT_ID'),
    getenv('MAYTES_CLIENT_SECRET'),
);
```

```go [Go]
import maytes "github.com/maytes/api-client-go"

api := maytes.CreateMaytesAPIClient(
    "https://api.maytes.co",
    os.Getenv("MAYTES_CLIENT_ID"),
    os.Getenv("MAYTES_CLIENT_SECRET"),
)
```

```java [Java]
import co.maytes.api.DefaultApi;
import co.maytes.api.auth.ClientFactory;

DefaultApi maytes = ClientFactory.create(
    "https://api.maytes.co",
    System.getenv("MAYTES_CLIENT_ID"),
    System.getenv("MAYTES_CLIENT_SECRET"));
```

```ruby [Ruby]
require 'maytes_api_client'

MAYTES = MaytesApiClient.create_maytes_api_client(
  endpoint: 'https://api.maytes.co',
  client_id: ENV['MAYTES_CLIENT_ID'],
  client_secret: ENV['MAYTES_CLIENT_SECRET'],
)
```

```csharp [.NET]
using MaytesApiClient.Auth;

var maytes = ClientFactory.Create(
    "https://api.maytes.co",
    Environment.GetEnvironmentVariable("MAYTES_CLIENT_ID"),
    Environment.GetEnvironmentVariable("MAYTES_CLIENT_SECRET"));
```

:::

In production, use `https://api.maytes.co`. During development, use the [sandbox endpoint](/sandbox-environment) and sandbox credentials. Later examples assume a `maytes` client configured as shown above.

## Two things that are true everywhere

**Amounts use integer minor units.** `4500` means **AUD 45.00**. Never send decimals in any monetary field.

**Capture moves money; authorization does not.** Payment places a *hold* on the customer's funds. Your capture call takes the funds. Until capture, nothing is settled, and the authorization is [auto-voided after 2 minutes](/capture-and-status#when-to-call-capture).

## Prefer raw HTTP?

Every operation is a JSON endpoint documented in the [API reference](/api-reference), including schemas, examples, and error codes. With raw HTTP:

* You must mint and refresh tokens yourself. See [Authentication](/authentication).
* **You should still verify webhooks with the SDK.** Verification needs no credentials and makes no network call, so it can run alongside your HTTP client.

## Next

Start with **[Create a checkout](/create-checkout)**.
