Developer docs v0.1.0

Schemas

Objects returned by the API.

Error

FieldTypeRequiredDescription
errorobjectyes
error.type"invalid_request_error" | "authentication_error" | "idempotency_error" | "card_error" | "api_error"yes
error.messagestringyesHuman-readable explanation.
error.codestringnoStable machine-readable identifier, e.g. resource_missing.
error.paramstring | nullnoFirst offending field; dotted for nested fields (recurring.interval).
error.request_idstringnoQuote this when reporting problems.
Example
{
  "error": {
    "type": "invalid_request_error",
    "message": "string",
    "code": "string",
    "param": "string",
    "request_id": "string"
  }
}

DeletedObject

FieldTypeRequiredDescription
objectstringyes
idstringyesULID · 26 chars
deletedbooleanyes
Example
{
  "object": "string",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "deleted": true
}

Account

A merchant account. The NETOPIA Payments API key is write-only and never returned.

FieldTypeRequiredDescription
object"account"no
idstringnoULID · 26 chars
namestringno
emailstring (email)no
first_namestring | nullnoNull until the person who signed in by email has entered their name.
last_namestring | nullno
is_livebooleannoTrue for a live account (sk_live_ keys), false for a test account (sk_test_ keys, NETOPIA Payments sandbox).
netopia_pos_signaturestring | nullnoNull until the NETOPIA Payments credentials are saved.
netopia_configuredbooleannoFalse while the account has no NETOPIA Payments credentials. Payments and enrollments fail with netopia_not_configured (409) until they are saved with POST /v1/account.
created_atstring (date-time)no
updated_atstring (date-time)no
can_switch_modebooleannoTrue when the request comes from a dashboard session that can switch between the live account and its linked test account. Always false for API keys.
can_syncbooleannoTrue for a dashboard session, which can sync products, prices and webhook endpoints from live into the test account. Always false for API keys.
Example
{
  "object": "account",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "name": "string",
  "email": "[email protected]",
  "first_name": "string",
  "last_name": "string",
  "is_live": false,
  "netopia_pos_signature": "string",
  "netopia_configured": false,
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z",
  "can_switch_mode": false,
  "can_sync": false
}

ApiKey

FieldTypeRequiredDescription
object"api_key"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
key_prefixstringnoFirst 12 characters, for identification.
namestringno
is_activebooleanno
last_used_atstring (date-time) | nullno
created_atstring (date-time)no
Example
{
  "object": "api_key",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "key_prefix": "string",
  "name": "string",
  "is_active": false,
  "last_used_at": "2026-10-25T18:00:00.000Z",
  "created_at": "2026-10-25T18:00:00.000Z"
}

ApiKeyWithSecret

FieldTypeRequiredDescription
object"api_key"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
key_prefixstringnoFirst 12 characters, for identification.
namestringno
is_activebooleanno
last_used_atstring (date-time) | nullno
created_atstring (date-time)no
keystringyesThe secret, shown once (matching keyed requests can replay it).
Example
{
  "object": "api_key",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "key_prefix": "string",
  "name": "string",
  "is_active": false,
  "last_used_at": "2026-10-25T18:00:00.000Z",
  "created_at": "2026-10-25T18:00:00.000Z",
  "key": "string"
}

Customer

Remote charges require the full billing object in metadata.billing (see NETOPIA.md).

FieldTypeRequiredDescription
object"customer"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
emailstring (email)no
namestring | nullno
phonestring | nullno
metadataobjectnoFree-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements.
created_atstring (date-time)no
updated_atstring (date-time)no
Example
{
  "object": "customer",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "email": "[email protected]",
  "name": "string",
  "phone": "string",
  "metadata": {},
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z"
}

Product

FieldTypeRequiredDescription
object"product"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
namestringno
descriptionstring | nullno
activebooleanno
metadataobjectnoFree-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements.
created_atstring (date-time)no
updated_atstring (date-time)no
Example
{
  "object": "product",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "name": "string",
  "description": "string",
  "active": false,
  "metadata": {},
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z"
}

Price

Amount, currency and interval are immutable; create a new price to change them.

FieldTypeRequiredDescription
object"price"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
product_idstringnoULID · 26 chars
activebooleanno
amountintegernoMinor units.
currency"RON" | "EUR" | "USD"noCurrency. Case-insensitive on input, stored uppercase.
recurringobjectno
recurring.interval"day" | "week" | "month" | "year"no
recurring.interval_countintegerno≥ 1
metadataobjectnoFree-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements.
created_atstring (date-time)no
Example
{
  "object": "price",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "product_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "active": false,
  "amount": 1,
  "currency": "RON",
  "recurring": {
    "interval": "day",
    "interval_count": 1
  },
  "metadata": {},
  "created_at": "2026-10-25T18:00:00.000Z"
}

Instrument

A reusable NETOPIA Payments token. The token itself is never returned.

FieldTypeRequiredDescription
object"instrument"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
customer_idstringnoULID · 26 chars
type"card" | "account" | "wallet"no
cardobject | nullnoPresent only when type is card; display data only.
card.last4string | nullno
card.brandstring | nullno
card.exp_monthinteger | nullno
card.exp_yearinteger | nullno
is_defaultbooleanno
enrollment_verified_atstring (date-time) | nullnoSet after verified hosted enrollment; remote billing requires it.
created_atstring (date-time)no
Example
{
  "object": "instrument",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "type": "card",
  "card": {
    "last4": "string",
    "brand": "string",
    "exp_month": 1,
    "exp_year": 1
  },
  "is_default": false,
  "enrollment_verified_at": "2026-10-25T18:00:00.000Z",
  "created_at": "2026-10-25T18:00:00.000Z"
}

Enrollment

A 0 RON hosted card enrollment that yields a verified reusable instrument.

FieldTypeRequiredDescription
object"enrollment"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
customer_idstringnoULID · 26 chars
status"pending" | "requires_action" | "processing" | "succeeded" | "failed"no
amount0no
currency"RON"no
netopia_ntp_idstring | nullno
instrument_idstring | nullnoSet once status is succeeded. · 26 chars
error_messagestring | nullno
checkout_urlstring | nullnoHosted NETOPIA Payments checkout; sensitive, present once status is requires_action. Do not log or share.
created_atstring (date-time)no
updated_atstring (date-time)no
return_urlstring (uri) | nullnoWhere the customer lands after hosted checkout, via Payware.
Example
{
  "object": "enrollment",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "status": "pending",
  "amount": 0,
  "currency": "RON",
  "netopia_ntp_id": "string",
  "instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "error_message": "string",
  "checkout_url": "string",
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z",
  "return_url": "https://example.com/hooks/payware"
}

SubscriptionItem

FieldTypeRequiredDescription
idstringnoULID · 26 chars
price_idstringnoULID · 26 chars
quantityintegerno≥ 1
metadataobjectnoFree-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements.
Example
{
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "quantity": 1,
  "metadata": {}
}

Subscription

FieldTypeRequiredDescription
object"subscription"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
customer_idstringnoULID · 26 chars
status"incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "unpaid" | "paused" | "canceled"noA 201 does not mean the customer has paid; check status.
default_instrument_idstring | nullnoULID · 26 chars
collection_method"charge_automatically"no
billing_cycle_anchorstring (date-time)no
current_period_startstring (date-time)no
current_period_endstring (date-time)no
trial_startstring (date-time) | nullno
trial_endstring (date-time) | nullno
cancel_atstring (date-time) | nullno
next_payment_attemptstring (date-time) | nullnoSet only while past_due.
cancel_at_period_endbooleanno
canceled_atstring (date-time) | nullno
ended_atstring (date-time) | nullno
pause_collectionobject | nullno
pause_collection.behavior"void"no
pause_collection.resumes_atstring (date-time) | nullno
metadataobjectnoFree-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements.
descriptionstring | nullno
itemsSubscriptionItem[]no
created_atstring (date-time)no
updated_atstring (date-time)no
Example
{
  "object": "subscription",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "status": "incomplete",
  "default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "collection_method": "charge_automatically",
  "billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
  "current_period_start": "2026-10-25T18:00:00.000Z",
  "current_period_end": "2026-10-25T18:00:00.000Z",
  "trial_start": "2026-10-25T18:00:00.000Z",
  "trial_end": "2026-10-25T18:00:00.000Z",
  "cancel_at": "2026-10-25T18:00:00.000Z",
  "next_payment_attempt": "2026-10-25T18:00:00.000Z",
  "cancel_at_period_end": false,
  "canceled_at": "2026-10-25T18:00:00.000Z",
  "ended_at": "2026-10-25T18:00:00.000Z",
  "pause_collection": {
    "behavior": "void",
    "resumes_at": "2026-10-25T18:00:00.000Z"
  },
  "metadata": {},
  "description": "string",
  "items": [
    {
      "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
      "price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
      "quantity": 1,
      "metadata": {}
    }
  ],
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z"
}

SubscriptionWithProration

FieldTypeRequiredDescription
object"subscription"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
customer_idstringnoULID · 26 chars
status"incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "unpaid" | "paused" | "canceled"noA 201 does not mean the customer has paid; check status.
default_instrument_idstring | nullnoULID · 26 chars
collection_method"charge_automatically"no
billing_cycle_anchorstring (date-time)no
current_period_startstring (date-time)no
current_period_endstring (date-time)no
trial_startstring (date-time) | nullno
trial_endstring (date-time) | nullno
cancel_atstring (date-time) | nullno
next_payment_attemptstring (date-time) | nullnoSet only while past_due.
cancel_at_period_endbooleanno
canceled_atstring (date-time) | nullno
ended_atstring (date-time) | nullno
pause_collectionobject | nullno
pause_collection.behavior"void"no
pause_collection.resumes_atstring (date-time) | nullno
metadataobjectnoFree-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements.
descriptionstring | nullno
itemsSubscriptionItem[]no
created_atstring (date-time)no
updated_atstring (date-time)no
proration_transactionPayment | nullnoThe proration charge when one was created, otherwise null.
Example
{
  "object": "subscription",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "status": "incomplete",
  "default_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "collection_method": "charge_automatically",
  "billing_cycle_anchor": "2026-10-25T18:00:00.000Z",
  "current_period_start": "2026-10-25T18:00:00.000Z",
  "current_period_end": "2026-10-25T18:00:00.000Z",
  "trial_start": "2026-10-25T18:00:00.000Z",
  "trial_end": "2026-10-25T18:00:00.000Z",
  "cancel_at": "2026-10-25T18:00:00.000Z",
  "next_payment_attempt": "2026-10-25T18:00:00.000Z",
  "cancel_at_period_end": false,
  "canceled_at": "2026-10-25T18:00:00.000Z",
  "ended_at": "2026-10-25T18:00:00.000Z",
  "pause_collection": {
    "behavior": "void",
    "resumes_at": "2026-10-25T18:00:00.000Z"
  },
  "metadata": {},
  "description": "string",
  "items": [
    {
      "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
      "price_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
      "quantity": 1,
      "metadata": {}
    }
  ],
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z",
  "proration_transaction": {
    "object": "payment",
    "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
    "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
    "subscription_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
    "customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
    "instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
    "amount": 1,
    "currency": "RON",
    "status": "pending",
    "netopia_ntp_id": "string",
    "netopia_status_code": 1,
    "error_message": "string",
    "period_start": "2026-10-25T18:00:00.000Z",
    "period_end": "2026-10-25T18:00:00.000Z",
    "description": "string",
    "metadata": {},
    "proration": false,
    "review": {
      "status": "open",
      "reason": "subscription_expired",
      "opened_at": "2026-10-25T18:00:00.000Z",
      "resolution": "refunded_externally",
      "note": "string",
      "resolved_at": "2026-10-25T18:00:00.000Z",
      "resolved_by_api_key_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C"
    },
    "created_at": "2026-10-25T18:00:00.000Z",
    "payment_link_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
    "payer_email": "string"
  }
}

Webhook

FieldTypeRequiredDescription
object"webhook"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
urlstring (uri)no
enabled_eventsEventType[]noEmpty means all events.
is_activebooleanno
created_atstring (date-time)no
updated_atstring (date-time)no
Example
{
  "object": "webhook",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "url": "https://example.com/hooks/payware",
  "enabled_events": [
    "customer.created"
  ],
  "is_active": false,
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z"
}

WebhookWithSecret

FieldTypeRequiredDescription
object"webhook"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
urlstring (uri)no
enabled_eventsEventType[]noEmpty means all events.
is_activebooleanno
created_atstring (date-time)no
updated_atstring (date-time)no
secretstringyesSigning secret (whsec_…), returned only here and on matching idempotency replays.
Example
{
  "object": "webhook",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "url": "https://example.com/hooks/payware",
  "enabled_events": [
    "customer.created"
  ],
  "is_active": false,
  "created_at": "2026-10-25T18:00:00.000Z",
  "updated_at": "2026-10-25T18:00:00.000Z",
  "secret": "string"
}

EventType

customer.created customer.updated customer.deleted subscription.created subscription.updated subscription.canceled subscription.paused subscription.resumed subscription.trial_will_end payment.succeeded payment.failed payment.review_required payment.review_resolved enrollment.created enrollment.updated enrollment.failed instrument.attached instrument.detached

WebhookEvent

One delivery record per event per webhook.

FieldTypeRequiredDescription
object"webhook_event"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
webhook_idstringnoULID · 26 chars
event_typeEventTypeno
payloadobjectnoThe delivered envelope.
status"pending" | "delivered" | "failed"no
attemptsintegerno
last_attempt_atstring (date-time) | nullno
next_retry_atstring (date-time) | nullno
created_atstring (date-time)no
Example
{
  "object": "webhook_event",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "webhook_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "event_type": "customer.created",
  "payload": {},
  "status": "pending",
  "attempts": 1,
  "last_attempt_at": "2026-10-25T18:00:00.000Z",
  "next_retry_at": "2026-10-25T18:00:00.000Z",
  "created_at": "2026-10-25T18:00:00.000Z"
}

PaymentReview

FieldTypeRequiredDescription
status"open" | "resolved"no
reason"subscription_expired" | "subscription_canceled"no
opened_atstring (date-time) | nullno
resolution"refunded_externally" | "service_provided"no
notestring | nullno
resolved_atstring (date-time) | nullno
resolved_by_api_key_idstring | nullnoULID · 26 chars
Example
{
  "status": "open",
  "reason": "subscription_expired",
  "opened_at": "2026-10-25T18:00:00.000Z",
  "resolution": "refunded_externally",
  "note": "string",
  "resolved_at": "2026-10-25T18:00:00.000Z",
  "resolved_by_api_key_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C"
}

Payment

One attempt to charge a stored instrument: either a subscription charge or a standalone payment.

FieldTypeRequiredDescription
object"payment"no
idstringnoULID · 26 chars
merchant_idstringnoULID · 26 chars
subscription_idstring | nullnoNull for standalone payments. · 26 chars
customer_idstring | nullnoNull for an anonymous payment made through a payment link. · 26 chars
instrument_idstring | nullnoULID · 26 chars
amountintegernoMinor units.
currency"RON" | "EUR" | "USD"noCurrency. Case-insensitive on input, stored uppercase.
status"pending" | "succeeded" | "failed" | "refunded"norefunded is reserved.
netopia_ntp_idstring | nullno
netopia_status_codeinteger | nullno
error_messagestring | nullno
period_startstring (date-time) | nullnoNull for standalone payments.
period_endstring (date-time) | nullnoNull for standalone payments.
descriptionstring | nullno
metadataobjectnoFree-form key/value data. Each value ≤16 KiB of JSON, ≤8 nesting levels, ≤100 properties/elements.
prorationbooleanno
reviewPaymentReviewno
created_atstring (date-time)no
payment_link_idstring | nullnoThe payment link this payment was made through, otherwise null. · 26 chars
payer_emailstring | nullnoEmail the payer entered on a payment link, otherwise null.
Example
{
  "object": "payment",
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "merchant_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "subscription_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "customer_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "amount": 1,
  "currency": "RON",
  "status": "pending",
  "netopia_ntp_id": "string",
  "netopia_status_code": 1,
  "error_message": "string",
  "period_start": "2026-10-25T18:00:00.000Z",
  "period_end": "2026-10-25T18:00:00.000Z",
  "description": "string",
  "metadata": {},
  "proration": false,
  "review": {
    "status": "open",
    "reason": "subscription_expired",
    "opened_at": "2026-10-25T18:00:00.000Z",
    "resolution": "refunded_externally",
    "note": "string",
    "resolved_at": "2026-10-25T18:00:00.000Z",
    "resolved_by_api_key_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C"
  },
  "created_at": "2026-10-25T18:00:00.000Z",
  "payment_link_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "payer_email": "string"
}

WebhookEnvelope

FieldTypeRequiredDescription
idstringyesLogical event ID; the same for every webhook that receives it. · 26 chars
object"event"yes
typeEventTypeyes
createdstring (date-time)yes
dataobjectyes
data.objectobjectnoThe full API object (subscription, customer, payment, instrument or enrollment); deletions carry {object, id, deleted: true}.
data.retry_atstring (date-time) | nullnopayment.failed only: next attempt, null when exhausted or standalone.
data.replacement_instrument_idstring | nullnoinstrument.detached only. · 26 chars
Example
{
  "id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C",
  "object": "event",
  "type": "customer.created",
  "created": "2026-10-25T18:00:00.000Z",
  "data": {
    "object": {},
    "retry_at": "2026-10-25T18:00:00.000Z",
    "replacement_instrument_id": "01JB9XK3M2R7TQ8N4V6Y0ZPA1C"
  }
}