Internal API Reference

Version: 1.0.0
Base URL: http://core:8000

This document describes the internal API endpoints used for service-to-service communication.


Authentication

All internal API endpoints require the X-Notifito-Internal-Secret header.

X-Notifito-Internal-Secret: your-internal-secret

This secret is shared between services and configured via the INTERNAL_SECRET environment variable.


Auth Endpoints

Login

Authenticates a seller user and returns tenant information.

Endpoint: POST /internal/auth/login

Authentication: Internal secret

Request Body

{
    "email": "owner@sneaker-store.test",
    "password": "password"
}
Field Type Required Description
email string Yes User email address
password string Yes User password

Response

200 OK

{
    "user": {
        "id": "user-123",
        "name": "Owner",
        "email": "owner@sneaker-store.test"
    },
    "tenant": {
        "id": "ten-456",
        "name": "Sneaker Store",
        "slug": "sneaker-store",
        "timezone": "UTC",
        "domains": ["shop.test"]
    }
}

401 Unauthorized

{
    "message": "These credentials do not match our records."
}

Examples

cURL

curl -X POST "http://core:8000/internal/auth/login" \
  -H "X-Notifito-Internal-Secret: your-secret" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "owner@sneaker-store.test",
    "password": "password"
  }'

PHP

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'X-Notifito-Internal-Secret' => config('notifito.internal_secret'),
])->post('http://core:8000/internal/auth/login', [
    'email' => 'owner@sneaker-store.test',
    'password' => 'password',
]);

$result = $response->json();

Item Type Endpoints

List Item Types

Returns all item types for a tenant.

Endpoint: GET /internal/tenants/{tenant}/item-types

Authentication: Internal secret

Parameters

Parameter Type Location Description
tenant string path Tenant UUID

Response

200 OK

{
    "item_types": [
        {
            "id": "it-123",
            "name": "Sneaker",
            "slug": "sneaker",
            "schema_version": 1,
            "attribute_count": 1,
            "item_count": 2
        }
    ]
}

Examples

cURL

curl "http://core:8000/internal/tenants/ten-456/item-types" \
  -H "X-Notifito-Internal-Secret: your-secret"

PHP

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'X-Notifito-Internal-Secret' => config('notifito.internal_secret'),
])->get("http://core:8000/internal/tenants/{$tenantId}/item-types");

$itemTypes = $response->json('item_types');

Get Item Type

Returns a specific item type with its schema and items.

Endpoint: GET /internal/tenants/{tenant}/item-types/{itemType}

Authentication: Internal secret

Parameters

Parameter Type Location Description
tenant string path Tenant UUID
itemType string path Item type UUID or slug

Response

200 OK

{
    "id": "it-123",
    "name": "Sneaker",
    "slug": "sneaker",
    "schema_version": 1,
    "attribute_schema": [
        {
            "key": "size",
            "label": "Size",
            "type": "enum",
            "options": ["40", "41", "42"],
            "required": true,
            "matchable": true,
            "multiple": false
        }
    ],
    "notify_policy": "all",
    "notify_factor": 3,
    "subscription_mode": "once",
    "action_url_template": null,
    "items": [
        {
            "id": "item-789",
            "name": "Air Max 90",
            "external_ref": "SKU-AM90"
        }
    ]
}

404 Not Found

{
    "message": "Unknown item type."
}

Create/Update Item Type

Creates a new item type or updates an existing one.

Endpoint: POST /internal/tenants/{tenant}/item-types

Authentication: Internal secret

Parameters

Parameter Type Location Description
tenant string path Tenant UUID

Request Body

{
    "id": null,
    "name": "Sneaker",
    "slug": "sneaker",
    "attribute_schema": [
        {
            "key": "size",
            "label": "Size",
            "type": "enum",
            "options": ["40", "41", "42"],
            "required": true,
            "matchable": true,
            "multiple": false
        }
    ],
    "notify_policy": "all",
    "notify_factor": 3,
    "subscription_mode": "once",
    "action_url_template": null
}
Field Type Required Description
id string No Item type UUID (for updates)
name string Yes Display name
slug string Yes URL-friendly identifier
attribute_schema array Yes Attribute definitions
notify_policy string Yes all or capacity_multiple
notify_factor integer Yes Capacity multiplier
subscription_mode string Yes once or recurring
action_url_template string No URL template

Response

200 OK

{
    "id": "it-123",
    "schema_version": 1
}

422 Unprocessable Entity

{
    "errors": {
        "attribute_schema": ["Attribute key [Bad Key] must be lowercase snake_case"]
    }
}

Examples

cURL

curl -X POST "http://core:8000/internal/tenants/ten-456/item-types" \
  -H "X-Notifito-Internal-Secret: your-secret" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Sneaker",
    "slug": "sneaker",
    "attribute_schema": [
        {
            "key": "size",
            "label": "Size",
            "type": "enum",
            "options": ["40", "41", "42"],
            "required": true,
            "matchable": true,
            "multiple": false
        }
    ],
    "notify_policy": "all",
    "notify_factor": 3,
    "subscription_mode": "once"
  }'

PHP

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'X-Notifito-Internal-Secret' => config('notifito.internal_secret'),
])->post("http://core:8000/internal/tenants/{$tenantId}/item-types", [
    'name' => 'Sneaker',
    'slug' => 'sneaker',
    'attribute_schema' => [
        [
            'key' => 'size',
            'label' => 'Size',
            'type' => 'enum',
            'options' => ['40', '41', '42'],
            'required' => true,
            'matchable' => true,
            'multiple' => false,
        ],
    ],
    'notify_policy' => 'all',
    'notify_factor' => 3,
    'subscription_mode' => 'once',
]);

$result = $response->json();

Subscription Endpoints

Create Subscription

Creates a new subscription (used by edge).

Endpoint: POST /internal/subscriptions

Authentication: Internal secret

Request Body

{
    "tenant_id": "ten-456",
    "item_type_id": "it-123",
    "item_id": null,
    "attributes": {
        "size": "42"
    },
    "channel": "email",
    "contact_value": "consumer@example.com",
    "source": "widget",
    "ip": "203.0.113.7",
    "user_agent": "Mozilla/5.0",
    "correlation_id": "corr-abc"
}

Response

202 Accepted

{
    "subscription_id": "sub-123",
    "was_created": true,
    "confirmation_sent": true
}

422 Unprocessable Entity

{
    "message": "The given data was invalid.",
    "errors": {
        "attributes.size": ["Size must be one of: 40, 41, 42."]
    }
}

Confirm Subscription

Confirms a subscription via token.

Endpoint: POST /internal/subscriptions/confirm

Authentication: Internal secret

Request Body

{
    "token": "confirmation-token-32-chars",
    "ip": "203.0.113.7",
    "user_agent": "Mozilla/5.0"
}

Response

200 OK

{
    "status": "active"
}

422 Unprocessable Entity

{
    "message": "Invalid or expired token.",
    "status": "invalid_token"
}

Unsubscribe

Unsubscribes via token.

Endpoint: POST /internal/subscriptions/unsubscribe

Authentication: Internal secret

Request Body

{
    "token": "unsubscribe-token-32-chars",
    "ip": "203.0.113.7",
    "user_agent": "Mozilla/5.0"
}

Response

200 OK

{
    "status": "unsubscribed"
}

Key Management Endpoints

Get Dashboard Key

Returns or creates a dashboard secret key for a tenant.

Endpoint: POST /internal/tenants/{tenant}/keys/dashboard

Authentication: Internal secret

Parameters

Parameter Type Location Description
tenant string path Tenant UUID

Response

200 OK

{
    "key": "sk_live_dashboardkey0000000"
}

404 Not Found

{
    "message": "No query results for model [App\\Models\\Tenant]."
}

Examples

cURL

curl -X POST "http://core:8000/internal/tenants/ten-456/keys/dashboard" \
  -H "X-Notifito-Internal-Secret: your-secret"

PHP

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'X-Notifito-Internal-Secret' => config('notifito.internal_secret'),
])->post("http://core:8000/internal/tenants/{$tenantId}/keys/dashboard");

$key = $response->json('key');

Key Resolution Endpoint

Resolve API Key

Resolves a publishable key to its tenant context.

Endpoint: POST /internal/keys/resolve

Authentication: Internal secret

Request Body

{
    "key": "pk_live_ADbaCjvo5TT1x8104zHXKSHr"
}

Response

200 OK

{
    "tenant_id": "ten-456",
    "tenant_name": "Sneaker Store",
    "tenant_slug": "sneaker-store",
    "tenant_domains": ["shop.test"]
}

404 Not Found

{
    "message": "Unknown API key."
}

Error Responses

All errors follow a consistent format:

{
    "message": "Human-readable error message",
    "errors": {
        "field": ["Validation error message"]
    }
}

HTTP Status Codes

Code Meaning
200 Success
202 Accepted
401 Unauthorized (missing or invalid internal secret)
404 Not Found
422 Validation Error
500 Internal Server Error

Related Documentation